diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-18 00:24:27 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-18 00:24:27 +0000 |
commit | b9558d5f86c471a125abf1fb3a3882fb053b1f8c (patch) | |
tree | 707b53ec64e740a7da87d5f36485e3cd9b1c794e /drivers/net | |
parent | b3ac367c7a3e6047abe74817db27e34e759f279f (diff) |
Merge with Linux 2.3.41.
Diffstat (limited to 'drivers/net')
36 files changed, 11742 insertions, 5294 deletions
diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 5425541ca..dc18256ce 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -573,7 +573,6 @@ static struct net_device eth0_dev = { /* Token-ring device probe */ extern int ibmtr_probe(struct net_device *); extern int olympic_probe(struct net_device *); -extern int tms380tr_probe(struct net_device *); extern int smctr_probe(struct net_device *); static int @@ -586,9 +585,6 @@ trif_probe(struct net_device *dev) #ifdef CONFIG_IBMOL && olympic_probe(dev) #endif -#ifdef CONFIG_SKTR - && tms380tr_probe(dev) -#endif #ifdef CONFIG_SMCTR && smctr_probe(dev) #endif diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index ead77eb9e..f15e31ae4 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -127,9 +127,6 @@ struct lance_private { int auto_select; /* cable-selection by carrier */ unsigned short busmaster_regval; -#ifdef CONFIG_AMIGA - unsigned int key; -#endif #ifdef CONFIG_SUNLANCE struct Linux_SBus_DMA *ledma; /* if set this points to ledma and arch=4m */ int burst_sizes; /* ledma SBus burst sizes */ @@ -740,78 +737,92 @@ static void lance_set_multicast (struct net_device *dev) int __init a2065_probe(struct net_device *dev) { - unsigned int key, is_cbm; - const struct ConfigDev *cd; - u_long board; - u_long sn; - struct lance_private *priv; - struct A2065Board *a2065; - - if ((key = is_cbm = zorro_find(ZORRO_PROD_CBM_A2065_1, 0, 0)) || - (key = is_cbm = zorro_find(ZORRO_PROD_CBM_A2065_2, 0, 0)) || - (key = zorro_find(ZORRO_PROD_AMERISTAR_A2065, 0, 0))) { - cd = zorro_get_board(key); - if ((board = (u_long)cd->cd_BoardAddr)) { - sn = cd->cd_Rom.er_SerialNumber; - if (is_cbm) { /* Commodore */ - dev->dev_addr[0] = 0x00; - dev->dev_addr[1] = 0x80; - dev->dev_addr[2] = 0x10; - } else { /* Ameristar */ - dev->dev_addr[0] = 0x00; - dev->dev_addr[1] = 0x00; - dev->dev_addr[2] = 0x9f; - } - dev->dev_addr[3] = (sn>>16) & 0xff; - dev->dev_addr[4] = (sn>>8) & 0xff; - dev->dev_addr[5] = sn & 0xff; - printk("%s: A2065 at 0x%08lx, Ethernet Address %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, board, dev->dev_addr[0], - dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], - dev->dev_addr[5]); - - init_etherdev(dev, 0); - - dev->priv = kmalloc(sizeof(struct - lance_private), - GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - priv = (struct lance_private *)dev->priv; - memset(priv, 0, sizeof(struct lance_private)); - - a2065 = (struct A2065Board *)ZTWO_VADDR(board); - priv->ll = &a2065->Lance; - priv->init_block = - (struct lance_init_block *)&a2065->RAM; - priv->lance_init_block = (struct lance_init_block *) - offsetof(struct A2065Board, RAM); - priv->auto_select = 0; - priv->key = key; - priv->busmaster_regval = LE_C3_BSWP; - - priv->lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS; - priv->lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS; - priv->rx_ring_mod_mask = RX_RING_MOD_MASK; - priv->tx_ring_mod_mask = TX_RING_MOD_MASK; - - dev->open = &lance_open; - dev->stop = &lance_close; - dev->hard_start_xmit = &lance_start_xmit; - dev->get_stats = &lance_get_stats; - dev->set_multicast_list = &lance_set_multicast; - dev->dma = 0; - - ether_setup(dev); - init_timer(&priv->multicast_timer); - priv->multicast_timer.data = (unsigned long) dev; - priv->multicast_timer.function = - (void (*)(unsigned long)) &lance_set_multicast; - - zorro_config_board(key, 0); - return(0); + struct zorro_dev *z = NULL; + + while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { + unsigned long board, base_addr, ram_start; + int is_cbm; + struct lance_private *priv; + + if (z->id == ZORRO_PROD_CBM_A2065_1 || + z->id == ZORRO_PROD_CBM_A2065_2) + is_cbm = 1; + else if (z->id == ZORRO_PROD_AMERISTAR_A2065) + is_cbm = 0; + else + continue; + + board = z->resource.start; + base_addr = board+A2065_LANCE; + ram_start = board+A2065_RAM; + + if (!request_mem_region(base_addr, sizeof(struct lance_regs), + "Am7990")) + continue; + if (!request_mem_region(ram_start, A2065_RAM_SIZE, "RAM")) { + release_mem_region(base_addr, + sizeof(struct lance_regs)); + continue; + } + strcpy(z->name, "A2065 Ethernet Card"); + if (is_cbm) { /* Commodore */ + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x80; + dev->dev_addr[2] = 0x10; + } else { /* Ameristar */ + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x00; + dev->dev_addr[2] = 0x9f; + } + dev->dev_addr[3] = (z->rom.er_SerialNumber>>16) & 0xff; + dev->dev_addr[4] = (z->rom.er_SerialNumber>>8) & 0xff; + dev->dev_addr[5] = z->rom.er_SerialNumber & 0xff; + printk("%s: A2065 at 0x%08lx, Ethernet Address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + init_etherdev(dev, 0); + + dev->priv = kmalloc(sizeof(struct lance_private), GFP_KERNEL); + if (dev->priv == NULL) { + release_mem_region(base_addr, + sizeof(struct lance_regs)); + release_mem_region(ram_start, A2065_RAM_SIZE); + return -ENOMEM; } + priv = (struct lance_private *)dev->priv; + memset(priv, 0, sizeof(struct lance_private)); + + dev->base_addr = ZTWO_VADDR(base_addr); + dev->mem_start = ZTWO_VADDR(ram_start); + dev->mem_end = dev->mem_start+A2065_RAM_SIZE; + + priv->ll = (volatile struct lance_regs *)dev->base_addr; + priv->init_block = (struct lance_init_block *)dev->mem_start; + priv->lance_init_block = (struct lance_init_block *)A2065_RAM; + priv->auto_select = 0; + priv->busmaster_regval = LE_C3_BSWP; + + priv->lance_log_rx_bufs = LANCE_LOG_RX_BUFFERS; + priv->lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS; + priv->rx_ring_mod_mask = RX_RING_MOD_MASK; + priv->tx_ring_mod_mask = TX_RING_MOD_MASK; + + dev->open = &lance_open; + dev->stop = &lance_close; + dev->hard_start_xmit = &lance_start_xmit; + dev->get_stats = &lance_get_stats; + dev->set_multicast_list = &lance_set_multicast; + dev->dma = 0; + + ether_setup(dev); + init_timer(&priv->multicast_timer); + priv->multicast_timer.data = (unsigned long) dev; + priv->multicast_timer.function = + (void (*)(unsigned long)) &lance_set_multicast; + + return(0); } return(-ENODEV); } @@ -845,7 +856,9 @@ void cleanup_module(void) struct lance_private *priv = (struct lance_private *)a2065_dev.priv; unregister_netdev(&a2065_dev); - zorro_unconfig_board(priv->key, 0); + release_mem_region(ZTWO_PADDR(a2065_dev.base_addr), + sizeof(struct lance_regs)); + release_mem_region(ZTWO_PADDR(a2065_dev.mem_start), A2065_RAM_SIZE); kfree(priv); } diff --git a/drivers/net/a2065.h b/drivers/net/a2065.h index db6e9e65d..f6e4d255f 100644 --- a/drivers/net/a2065.h +++ b/drivers/net/a2065.h @@ -169,9 +169,8 @@ struct lance_tx_desc { * A2065 Expansion Board Structure */ -struct A2065Board { - u_char Pad1[0x4000]; - volatile struct lance_regs Lance; - u_char Pad2[0x3ffc]; - volatile u_char RAM[0x8000]; -}; +#define A2065_LANCE 0x4000 + +#define A2065_RAM 0x8000 +#define A2065_RAM_SIZE 0x8000 + diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 75bff9f36..099bd1300 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -96,17 +96,15 @@ int ariadne_debug = 1; */ struct ariadne_private { - struct AriadneBoard *board; - struct TDRE *tx_ring[TX_RING_SIZE]; - struct RDRE *rx_ring[RX_RING_SIZE]; - u_short *tx_buff[TX_RING_SIZE]; - u_short *rx_buff[RX_RING_SIZE]; + volatile struct TDRE *tx_ring[TX_RING_SIZE]; + volatile struct RDRE *rx_ring[RX_RING_SIZE]; + volatile u_short *tx_buff[TX_RING_SIZE]; + volatile u_short *rx_buff[RX_RING_SIZE]; int cur_tx, cur_rx; /* The next free ring entry */ int dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; char tx_full; unsigned long lock; - unsigned int key; }; @@ -134,7 +132,7 @@ static void set_multicast_list(struct net_device *dev); #endif -static void memcpyw(u_short *dest, u_short *src, int len) +static void memcpyw(volatile u_short *dest, u_short *src, int len) { while (len >= 2) { *(dest++) = *(src++); @@ -147,71 +145,76 @@ static void memcpyw(u_short *dest, u_short *src, int len) int __init ariadne_probe(struct net_device *dev) { - unsigned int key; - const struct ConfigDev *cd; - u_long board; - struct ariadne_private *priv; - - /* Ethernet is part 0, Parallel is part 1 */ - if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_ARIADNE, 0, 0))) { - cd = zorro_get_board(key); - if ((board = (u_long)cd->cd_BoardAddr)) { - dev->dev_addr[0] = 0x00; - dev->dev_addr[1] = 0x60; - dev->dev_addr[2] = 0x30; - dev->dev_addr[3] = (cd->cd_Rom.er_SerialNumber>>16)&0xff; - dev->dev_addr[4] = (cd->cd_Rom.er_SerialNumber>>8)&0xff; - dev->dev_addr[5] = cd->cd_Rom.er_SerialNumber&0xff; - printk("%s: Ariadne at 0x%08lx, Ethernet Address " - "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - - init_etherdev(dev, 0); - - dev->priv = kmalloc(sizeof(struct ariadne_private), GFP_KERNEL); - if (dev->priv == NULL) - return -ENOMEM; - priv = (struct ariadne_private *)dev->priv; - memset(priv, 0, sizeof(struct ariadne_private)); - - priv->board = (struct AriadneBoard *)ZTWO_VADDR(board); - priv->key = key; - - dev->open = &ariadne_open; - dev->stop = &ariadne_close; - dev->hard_start_xmit = &ariadne_start_xmit; - dev->get_stats = &ariadne_get_stats; - dev->set_multicast_list = &set_multicast_list; - - zorro_config_board(key, 0); - return(0); + struct zorro_dev *z = NULL; + + while ((z = zorro_find_device(ZORRO_PROD_VILLAGE_TRONIC_ARIADNE, z))) { + unsigned long board = z->resource.start; + unsigned long base_addr = board+ARIADNE_LANCE; + unsigned long ram_start = board+ARIADNE_RAM; + + if (!request_mem_region(base_addr, sizeof(struct Am79C960), + "Am79C960")) + continue; + if (!request_mem_region(ram_start, ARIADNE_RAM_SIZE, "RAM")) { + release_mem_region(base_addr, sizeof(struct Am79C960)); + continue; } + strcpy(z->name, "Ariadne Ethernet Card and Parallel Ports"); + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x60; + dev->dev_addr[2] = 0x30; + dev->dev_addr[3] = (z->rom.er_SerialNumber>>16)&0xff; + dev->dev_addr[4] = (z->rom.er_SerialNumber>>8)&0xff; + dev->dev_addr[5] = z->rom.er_SerialNumber&0xff; + printk("%s: Ariadne at 0x%08lx, Ethernet Address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + init_etherdev(dev, 0); + + dev->priv = kmalloc(sizeof(struct ariadne_private), GFP_KERNEL); + if (dev->priv == NULL) { + release_mem_region(base_addr, sizeof(struct Am79C960)); + release_mem_region(ram_start, ARIADNE_RAM_SIZE); + return -ENOMEM; + } + memset(dev->priv, 0, sizeof(struct ariadne_private)); + + dev->base_addr = ZTWO_VADDR(base_addr); + dev->mem_start = ZTWO_VADDR(ram_start); + dev->mem_end = dev->mem_start+ARIADNE_RAM_SIZE; + + dev->open = &ariadne_open; + dev->stop = &ariadne_close; + dev->hard_start_xmit = &ariadne_start_xmit; + dev->get_stats = &ariadne_get_stats; + dev->set_multicast_list = &set_multicast_list; + + return 0; } - return(ENODEV); + return -ENODEV; } static int ariadne_open(struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; - struct AriadneBoard *board = priv->board; - struct lancedata *lancedata; + volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; u_short in; u_long version; /* Reset the LANCE */ - in = board->Lance.Reset; + in = lance->Reset; /* Stop the LANCE */ - board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ - board->Lance.RDP = STOP; + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RDP = STOP; /* Check the LANCE version */ - board->Lance.RAP = CSR88; /* Chip ID */ - version = swapw(board->Lance.RDP); - board->Lance.RAP = CSR89; /* Chip ID */ - version |= swapw(board->Lance.RDP)<<16; + lance->RAP = CSR88; /* Chip ID */ + version = swapw(lance->RDP); + lance->RAP = CSR89; /* Chip ID */ + version |= swapw(lance->RDP)<<16; if ((version & 0x00000fff) != 0x00000003) { printk("ariadne_open: Couldn't find AMD Ethernet Chip\n"); return(-EAGAIN); @@ -229,64 +232,62 @@ static int ariadne_open(struct net_device *dev) ariadne_init_ring(dev); /* Miscellaneous Stuff */ - board->Lance.RAP = CSR3; /* Interrupt Masks and Deferral Control */ - board->Lance.RDP = 0x0000; - board->Lance.RAP = CSR4; /* Test and Features Control */ - board->Lance.RDP = DPOLL|APAD_XMT|MFCOM|RCVCCOM|TXSTRTM|JABM; + lance->RAP = CSR3; /* Interrupt Masks and Deferral Control */ + lance->RDP = 0x0000; + lance->RAP = CSR4; /* Test and Features Control */ + lance->RDP = DPOLL|APAD_XMT|MFCOM|RCVCCOM|TXSTRTM|JABM; /* Set the Multicast Table */ - board->Lance.RAP = CSR8; /* Logical Address Filter, LADRF[15:0] */ - board->Lance.RDP = 0x0000; - board->Lance.RAP = CSR9; /* Logical Address Filter, LADRF[31:16] */ - board->Lance.RDP = 0x0000; - board->Lance.RAP = CSR10; /* Logical Address Filter, LADRF[47:32] */ - board->Lance.RDP = 0x0000; - board->Lance.RAP = CSR11; /* Logical Address Filter, LADRF[63:48] */ - board->Lance.RDP = 0x0000; + lance->RAP = CSR8; /* Logical Address Filter, LADRF[15:0] */ + lance->RDP = 0x0000; + lance->RAP = CSR9; /* Logical Address Filter, LADRF[31:16] */ + lance->RDP = 0x0000; + lance->RAP = CSR10; /* Logical Address Filter, LADRF[47:32] */ + lance->RDP = 0x0000; + lance->RAP = CSR11; /* Logical Address Filter, LADRF[63:48] */ + lance->RDP = 0x0000; /* Set the Ethernet Hardware Address */ - board->Lance.RAP = CSR12; /* Physical Address Register, PADR[15:0] */ - board->Lance.RDP = ((u_short *)&dev->dev_addr[0])[0]; - board->Lance.RAP = CSR13; /* Physical Address Register, PADR[31:16] */ - board->Lance.RDP = ((u_short *)&dev->dev_addr[0])[1]; - board->Lance.RAP = CSR14; /* Physical Address Register, PADR[47:32] */ - board->Lance.RDP = ((u_short *)&dev->dev_addr[0])[2]; + lance->RAP = CSR12; /* Physical Address Register, PADR[15:0] */ + lance->RDP = ((u_short *)&dev->dev_addr[0])[0]; + lance->RAP = CSR13; /* Physical Address Register, PADR[31:16] */ + lance->RDP = ((u_short *)&dev->dev_addr[0])[1]; + lance->RAP = CSR14; /* Physical Address Register, PADR[47:32] */ + lance->RDP = ((u_short *)&dev->dev_addr[0])[2]; /* Set the Init Block Mode */ - board->Lance.RAP = CSR15; /* Mode Register */ - board->Lance.RDP = 0x0000; - - lancedata = (struct lancedata *)offsetof(struct AriadneBoard, RAM); + lance->RAP = CSR15; /* Mode Register */ + lance->RDP = 0x0000; /* Set the Transmit Descriptor Ring Pointer */ - board->Lance.RAP = CSR30; /* Base Address of Transmit Ring */ - board->Lance.RDP = swloww((u_long)&lancedata->tx_ring); - board->Lance.RAP = CSR31; /* Base Address of transmit Ring */ - board->Lance.RDP = swhighw((u_long)&lancedata->tx_ring); + lance->RAP = CSR30; /* Base Address of Transmit Ring */ + lance->RDP = swloww(ARIADNE_RAM+offsetof(struct lancedata, tx_ring)); + lance->RAP = CSR31; /* Base Address of transmit Ring */ + lance->RDP = swhighw(ARIADNE_RAM+offsetof(struct lancedata, tx_ring)); /* Set the Receive Descriptor Ring Pointer */ - board->Lance.RAP = CSR24; /* Base Address of Receive Ring */ - board->Lance.RDP = swloww((u_long)&lancedata->rx_ring); - board->Lance.RAP = CSR25; /* Base Address of Receive Ring */ - board->Lance.RDP = swhighw((u_long)&lancedata->rx_ring); + lance->RAP = CSR24; /* Base Address of Receive Ring */ + lance->RDP = swloww(ARIADNE_RAM+offsetof(struct lancedata, rx_ring)); + lance->RAP = CSR25; /* Base Address of Receive Ring */ + lance->RDP = swhighw(ARIADNE_RAM+offsetof(struct lancedata, rx_ring)); /* Set the Number of RX and TX Ring Entries */ - board->Lance.RAP = CSR76; /* Receive Ring Length */ - board->Lance.RDP = swapw(((u_short)-RX_RING_SIZE)); - board->Lance.RAP = CSR78; /* Transmit Ring Length */ - board->Lance.RDP = swapw(((u_short)-TX_RING_SIZE)); + lance->RAP = CSR76; /* Receive Ring Length */ + lance->RDP = swapw(((u_short)-RX_RING_SIZE)); + lance->RAP = CSR78; /* Transmit Ring Length */ + lance->RDP = swapw(((u_short)-TX_RING_SIZE)); /* Enable Media Interface Port Auto Select (10BASE-2/10BASE-T) */ - board->Lance.RAP = ISACSR2; /* Miscellaneous Configuration */ - board->Lance.IDP = ASEL; + lance->RAP = ISACSR2; /* Miscellaneous Configuration */ + lance->IDP = ASEL; /* LED Control */ - board->Lance.RAP = ISACSR5; /* LED1 Status */ - board->Lance.IDP = PSE|XMTE; - board->Lance.RAP = ISACSR6; /* LED2 Status */ - board->Lance.IDP = PSE|COLE; - board->Lance.RAP = ISACSR7; /* LED3 Status */ - board->Lance.IDP = PSE|RCVE; + lance->RAP = ISACSR5; /* LED1 Status */ + lance->IDP = PSE|XMTE; + lance->RAP = ISACSR6; /* LED2 Status */ + lance->IDP = PSE|COLE; + lance->RAP = ISACSR7; /* LED3 Status */ + lance->IDP = PSE|RCVE; dev->tbusy = 0; dev->interrupt = 0; @@ -296,8 +297,8 @@ static int ariadne_open(struct net_device *dev) "Ariadne Ethernet", dev)) return(-EAGAIN); - board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ - board->Lance.RDP = INEA|STRT; + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RDP = INEA|STRT; MOD_INC_USE_COUNT; @@ -308,45 +309,42 @@ static int ariadne_open(struct net_device *dev) static void ariadne_init_ring(struct net_device *dev) { struct ariadne_private *priv = (struct ariadne_private *)dev->priv; - struct AriadneBoard *board = priv->board; - struct lancedata *lancedata; /* LANCE point of view */ - struct lancedata *alancedata; /* Amiga point of view */ + volatile struct lancedata *lancedata = (struct lancedata *)dev->mem_start; int i; priv->lock = 0, priv->tx_full = 0; priv->cur_rx = priv->cur_tx = 0; priv->dirty_tx = 0; - lancedata = (struct lancedata *)offsetof(struct AriadneBoard, RAM); - alancedata = (struct lancedata *)board->RAM; - /* Set up TX Ring */ for (i = 0; i < TX_RING_SIZE; i++) { - alancedata->tx_ring[i].TMD0 = swloww((u_long)lancedata->tx_buff[i]); - alancedata->tx_ring[i].TMD1 = swhighw((u_long)lancedata->tx_buff[i])|TF_STP|TF_ENP; - alancedata->tx_ring[i].TMD2 = swapw((u_short)-PKT_BUF_SIZE); - alancedata->tx_ring[i].TMD3 = 0; - priv->tx_ring[i] = &alancedata->tx_ring[i]; - priv->tx_buff[i] = alancedata->tx_buff[i]; + volatile struct TDRE *t = &lancedata->tx_ring[i]; + t->TMD0 = swloww(ARIADNE_RAM+offsetof(struct lancedata, tx_buff[i])); + t->TMD1 = swhighw(ARIADNE_RAM+offsetof(struct lancedata, tx_buff[i])) | + TF_STP | TF_ENP; + t->TMD2 = swapw((u_short)-PKT_BUF_SIZE); + t->TMD3 = 0; + priv->tx_ring[i] = &lancedata->tx_ring[i]; + priv->tx_buff[i] = lancedata->tx_buff[i]; #if 0 - printk("TX Entry %2d @ 0x%08x (LANCE 0x%08x), Buf @ 0x%08x (LANCE 0x%08x)\n", - i, (int)&alancedata->tx_ring[i], (int)&lancedata->tx_ring[i], - (int)alancedata->tx_buff[i], (int)lancedata->tx_buff[i]); + printk("TX Entry %2d at %p, Buf at %p\n", i, &lancedata->tx_ring[i], + lancedata->tx_buff[i]); #endif } /* Set up RX Ring */ for (i = 0; i < RX_RING_SIZE; i++) { - alancedata->rx_ring[i].RMD0 = swloww((u_long)lancedata->rx_buff[i]); - alancedata->rx_ring[i].RMD1 = swhighw((u_long)lancedata->rx_buff[i])|RF_OWN; - alancedata->rx_ring[i].RMD2 = swapw((u_short)-PKT_BUF_SIZE); - alancedata->rx_ring[i].RMD3 = 0x0000; - priv->rx_ring[i] = &alancedata->rx_ring[i]; - priv->rx_buff[i] = alancedata->rx_buff[i]; + volatile struct RDRE *r = &lancedata->rx_ring[i]; + r->RMD0 = swloww(ARIADNE_RAM+offsetof(struct lancedata, rx_buff[i])); + r->RMD1 = swhighw(ARIADNE_RAM+offsetof(struct lancedata, rx_buff[i])) | + RF_OWN; + r->RMD2 = swapw((u_short)-PKT_BUF_SIZE); + r->RMD3 = 0x0000; + priv->rx_ring[i] = &lancedata->rx_ring[i]; + priv->rx_buff[i] = lancedata->rx_buff[i]; #if 0 - printk("RX Entry %2d @ 0x%08x (LANCE 0x%08x), Buf @ 0x%08x (LANCE 0x%08x)\n", - i, (int)&alancedata->rx_ring[i], (int)&lancedata->rx_ring[i], - (int)alancedata->rx_buff[i], (int)lancedata->rx_buff[i]); + printk("RX Entry %2d at %p, Buf at %p\n", i, &lancedata->rx_ring[i], + lancedata->rx_buff[i]); #endif } } @@ -355,24 +353,24 @@ static void ariadne_init_ring(struct net_device *dev) static int ariadne_close(struct net_device *dev) { struct ariadne_private *priv = (struct ariadne_private *)dev->priv; - struct AriadneBoard *board = priv->board; + volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; dev->start = 0; dev->tbusy = 1; - board->Lance.RAP = CSR112; /* Missed Frame Count */ - priv->stats.rx_missed_errors = swapw(board->Lance.RDP); - board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RAP = CSR112; /* Missed Frame Count */ + priv->stats.rx_missed_errors = swapw(lance->RDP); + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ if (ariadne_debug > 1) { printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, - board->Lance.RDP); + lance->RDP); printk("%s: %lu packets missed\n", dev->name, priv->stats.rx_missed_errors); } /* We stop the LANCE here -- it occasionally polls memory if we don't. */ - board->Lance.RDP = STOP; + lance->RDP = STOP; free_irq(IRQ_AMIGA_PORTS, dev); @@ -385,21 +383,18 @@ static int ariadne_close(struct net_device *dev) static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp) { struct net_device *dev = (struct net_device *)data; + volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; struct ariadne_private *priv; - struct AriadneBoard *board; - int csr0, boguscnt = 10; + int csr0, boguscnt; if (dev == NULL) { printk("ariadne_interrupt(): irq for unknown device.\n"); return; } - priv = (struct ariadne_private *)dev->priv; - board = priv->board; - - board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ - if (!(board->Lance.RDP & INTR)) /* Check if any interrupt has been */ + if (!(lance->RDP & INTR)) /* Check if any interrupt has been */ return; /* generated by the board. */ if (dev->interrupt) @@ -407,14 +402,17 @@ static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp) dev->interrupt = 1; - while ((csr0 = board->Lance.RDP) & (ERR|RINT|TINT) && --boguscnt >= 0) { + priv = (struct ariadne_private *)dev->priv; + + boguscnt = 10; + while ((csr0 = lance->RDP) & (ERR|RINT|TINT) && --boguscnt >= 0) { /* Acknowledge all of the current interrupt sources ASAP. */ - board->Lance.RDP = csr0 & ~(INEA|TDMD|STOP|STRT|INIT); + lance->RDP = csr0 & ~(INEA|TDMD|STOP|STRT|INIT); #if 0 if (ariadne_debug > 5) { printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.", dev->name, - csr0, board->Lance.RDP); + csr0, lance->RDP); printk("["); if (csr0 & INTR) printk(" INTR"); @@ -484,7 +482,7 @@ static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp) printk("%s: Tx FIFO error! Status %4.4x.\n", dev->name, csr0); /* Restart the chip. */ - board->Lance.RDP = STRT; + lance->RDP = STRT; } } else { if (status & (TF_MORE|TF_ONE)) @@ -522,18 +520,18 @@ static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp) printk("%s: Bus master arbitration failure, status %4.4x.\n", dev->name, csr0); /* Restart the chip. */ - board->Lance.RDP = STRT; + lance->RDP = STRT; } } /* Clear any other interrupt, and set interrupt enable. */ - board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ - board->Lance.RDP = INEA|BABL|CERR|MISS|MERR|IDON; + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RDP = INEA|BABL|CERR|MISS|MERR|IDON; #if 0 if (ariadne_debug > 4) - printk("%s: exiting interrupt, csr%d=%#4.4x.\n", dev->name, - board->Lance.RAP, board->Lance.RDP); + printk("%s: exiting interrupt, csr%d=%#4.4x.\n", dev->name, lance->RAP, + lance->RDP); #endif dev->interrupt = 0; @@ -544,7 +542,7 @@ static void ariadne_interrupt(int irq, void *data, struct pt_regs *fp) static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ariadne_private *priv = (struct ariadne_private *)dev->priv; - struct AriadneBoard *board = priv->board; + volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; int entry; unsigned long flags; @@ -553,10 +551,10 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) int tickssofar = jiffies - dev->trans_start; if (tickssofar < 20) return(1); - board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ printk("%s: transmit timed out, status %4.4x, resetting.\n", dev->name, - board->Lance.RDP); - board->Lance.RDP = STOP; + lance->RDP); + lance->RDP = STOP; priv->stats.tx_errors++; #ifndef final_version { @@ -566,17 +564,20 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) priv->cur_rx); for (i = 0 ; i < RX_RING_SIZE; i++) printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", - (swapw((priv->rx_ring[i]->RMD1))<<16)|swapw(priv->rx_ring[i]->RMD0), - swapw(-priv->rx_ring[i]->RMD2), swapw(priv->rx_ring[i]->RMD3)); + (swapw((priv->rx_ring[i]->RMD1))<<16) | + swapw(priv->rx_ring[i]->RMD0), + swapw(-priv->rx_ring[i]->RMD2), + swapw(priv->rx_ring[i]->RMD3)); for (i = 0 ; i < TX_RING_SIZE; i++) printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", - (swapw((priv->tx_ring[i]->TMD1))<<16)|swapw(priv->tx_ring[i]->TMD0), + (swapw((priv->tx_ring[i]->TMD1))<<16) | + swapw(priv->tx_ring[i]->TMD0), swapw(-priv->tx_ring[i]->TMD2), priv->tx_ring[i]->TMD3); printk("\n"); } #endif ariadne_init_ring(dev); - board->Lance.RDP = INEA|STRT; + lance->RDP = INEA|STRT; dev->tbusy = 0; dev->trans_start = jiffies; @@ -586,10 +587,10 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) #if 0 if (ariadne_debug > 3) { - board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ printk("%s: ariadne_start_xmit() called, csr0 %4.4x.\n", dev->name, - board->Lance.RDP); - board->Lance.RDP = 0x0000; + lance->RDP); + lance->RDP = 0x0000; } #endif @@ -675,8 +676,8 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* Trigger an immediate send poll. */ - board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ - board->Lance.RDP = INEA|TDMD; + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RDP = INEA|TDMD; dev->trans_start = jiffies; @@ -782,16 +783,16 @@ static int ariadne_rx(struct net_device *dev) static struct net_device_stats *ariadne_get_stats(struct net_device *dev) { struct ariadne_private *priv = (struct ariadne_private *)dev->priv; - struct AriadneBoard *board = priv->board; + volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; short saved_addr; unsigned long flags; save_flags(flags); cli(); - saved_addr = board->Lance.RAP; - board->Lance.RAP = CSR112; /* Missed Frame Count */ - priv->stats.rx_missed_errors = swapw(board->Lance.RDP); - board->Lance.RAP = saved_addr; + saved_addr = lance->RAP; + lance->RAP = CSR112; /* Missed Frame Count */ + priv->stats.rx_missed_errors = swapw(lance->RDP); + lance->RAP = saved_addr; restore_flags(flags); return(&priv->stats); @@ -806,18 +807,18 @@ static struct net_device_stats *ariadne_get_stats(struct net_device *dev) */ static void set_multicast_list(struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; - struct AriadneBoard *board = priv->board; + volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; /* We take the simple way out and always enable promiscuous mode. */ - board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ - board->Lance.RDP = STOP; /* Temporarily stop the lance. */ + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RDP = STOP; /* Temporarily stop the lance. */ + ariadne_init_ring(dev); if (dev->flags & IFF_PROMISC) { /* Log any net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); - board->Lance.RAP = CSR15; /* Mode Register */ - board->Lance.RDP = PROM; /* Set promiscuous mode */ + lance->RAP = CSR15; /* Mode Register */ + lance->RDP = PROM; /* Set promiscuous mode */ } else { short multicast_table[4]; int num_addrs = dev->mc_count; @@ -826,15 +827,15 @@ static void set_multicast_list(struct net_device *dev) memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table)); for (i = 0; i < 4; i++) { - board->Lance.RAP = CSR8+(i<<8); /* Logical Address Filter */ - board->Lance.RDP = swapw(multicast_table[i]); + lance->RAP = CSR8+(i<<8); /* Logical Address Filter */ + lance->RDP = swapw(multicast_table[i]); } - board->Lance.RAP = CSR15; /* Mode Register */ - board->Lance.RDP = 0x0000; /* Unset promiscuous mode */ + lance->RAP = CSR15; /* Mode Register */ + lance->RDP = 0x0000; /* Unset promiscuous mode */ } - board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ - board->Lance.RDP = INEA|STRT|IDON; /* Resume normal operation. */ + lance->RAP = CSR0; /* PCnet-ISA Controller Status */ + lance->RDP = INEA|STRT|IDON; /* Resume normal operation. */ } @@ -866,7 +867,9 @@ void cleanup_module(void) struct ariadne_private *priv = (struct ariadne_private *)ariadne_dev.priv; unregister_netdev(&ariadne_dev); - zorro_unconfig_board(priv->key, 0); + release_mem_region(ZTWO_PADDR(ariadne_dev.base_addr), + sizeof(struct Am79C960)); + release_mem_region(ZTWO_PADDR(ariadne_dev.mem_start), ARIADNE_RAM_SIZE); kfree(priv); } diff --git a/drivers/net/ariadne.h b/drivers/net/ariadne.h index 2ba188134..f7913d5a3 100644 --- a/drivers/net/ariadne.h +++ b/drivers/net/ariadne.h @@ -403,12 +403,13 @@ struct MC68230 { * Ariadne Expansion Board Structure */ -struct AriadneBoard { - u_char Pad1[0x360]; - struct Am79C960 Lance; - u_char Pad2[0xc88]; - struct MC68230 PiT; - u_char Pad3[0x2fc0]; - volatile u_short BootPROM[0x2000]; /* I guess it's here :-) */ - volatile u_short RAM[0x4000]; /* Always access WORDs!! */ -}; +#define ARIADNE_LANCE 0x360 + +#define ARIADNE_PIT 0x1000 + +#define ARIADNE_BOOTPROM 0x4000 /* I guess it's here :-) */ +#define ARIADNE_BOOTPROM_SIZE 0x4000 + +#define ARIADNE_RAM 0x8000 /* Always access WORDs!! */ +#define ARIADNE_RAM_SIZE 0x8000 + diff --git a/drivers/net/ariadne2.c b/drivers/net/ariadne2.c index 10edf1e79..14ab3f321 100644 --- a/drivers/net/ariadne2.c +++ b/drivers/net/ariadne2.c @@ -66,8 +66,7 @@ #define WORDSWAP(a) ((((a)>>8)&0xff) | ((a)<<8)) int ariadne2_probe(struct net_device *dev); -static int ariadne2_init(struct net_device *dev, unsigned int key, - unsigned long board); +static int ariadne2_init(struct net_device *dev, unsigned long board); static int ariadne2_open(struct net_device *dev); static int ariadne2_close(struct net_device *dev); @@ -83,25 +82,26 @@ static void ariadne2_block_output(struct net_device *dev, const int count, int __init ariadne2_probe(struct net_device *dev) { - unsigned int key; - const struct ConfigDev *cd; - u_long board; + struct zorro_dev *z = NULL; + unsigned long board, ioaddr; int err; - if ((key = zorro_find(ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2, 0, 0))) { - cd = zorro_get_board(key); - if ((board = (u_long)cd->cd_BoardAddr)) { - if ((err = ariadne2_init(dev, key, ZTWO_VADDR(board)))) - return err; - zorro_config_board(key, 0); - return 0; + while ((z = zorro_find_device(ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2, z))) { + board = z->resource.start; + ioaddr = board+ARIADNE2_BASE*2; + if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, "RTL8019AS")) + continue; + if ((err = ariadne2_init(dev, ZTWO_VADDR(board)))) { + release_mem_region(ioaddr, NE_IO_EXTENT*2); + return err; } + strcpy(z->name, "AriadNE2 Ethernet"); + return 0; } return -ENODEV; } -static int __init ariadne2_init(struct net_device *dev, unsigned int key, - unsigned long board) +static int __init ariadne2_init(struct net_device *dev, unsigned long board) { int i; unsigned char SA_prom[32]; @@ -111,7 +111,7 @@ static int __init ariadne2_init(struct net_device *dev, unsigned int key, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - int ioaddr = board+ARIADNE2_BASE*2; + unsigned long ioaddr = board+ARIADNE2_BASE*2; if (load_8390_module("ariadne2.c")) return -ENOSYS; @@ -189,7 +189,6 @@ static int __init ariadne2_init(struct net_device *dev, unsigned int key, printk("Unable to get memory for dev->priv.\n"); return -ENOMEM; } - ((struct ei_device *)dev->priv)->priv = key; for(i = 0; i < ETHER_ADDR_LEN; i++) { #ifdef DEBUG @@ -417,10 +416,9 @@ int init_module(void) void cleanup_module(void) { - unsigned int key = ((struct ei_device *)ariadne2_dev.priv)->priv; free_irq(IRQ_AMIGA_PORTS, &ariadne2_dev); + release_mem_region(ZTWO_PADDR(ariadne2_dev.base_addr), NE_IO_EXTENT*2); unregister_netdev(&ariadne2_dev); - zorro_unconfig_board(key, 0); unlock_8390_module(); } diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index e319463be..0b04615ef 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -9,6 +9,7 @@ * Many modifications, and currently maintained, by * Philip Blundell <Philip.Blundell@pobox.com> * Added the Compaq LTE Alan Cox <alan@redhat.com> + * Added MCA support Adam Fritzler <mid@auk.cx> * * Note - this driver is experimental still - it has problems on faster * machines. Someone needs to sit down and go through it line by line with @@ -120,6 +121,7 @@ #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/malloc.h> +#include <linux/mca.h> #include <linux/spinlock.h> @@ -232,6 +234,16 @@ static unsigned short start_code[] = { /* maps irq number to EtherExpress magic value */ static char irqrmap[] = { 0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0 }; +#ifdef CONFIG_MCA +/* mapping of the first four bits of the second POS register */ +static unsigned short mca_iomap[] = { + 0x270, 0x260, 0x250, 0x240, 0x230, 0x220, 0x210, 0x200, + 0x370, 0x360, 0x350, 0x340, 0x330, 0x320, 0x310, 0x300 +}; +/* bits 5-7 of the second POS register */ +static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 }; +#endif + /* * Prototypes for Linux interface */ @@ -331,6 +343,55 @@ int __init express_probe(struct net_device *dev) static unsigned short ports[] = { 0x300,0x310,0x270,0x320,0x340,0 }; unsigned short ioaddr = dev->base_addr; + dev->if_port = 0xff; /* not set */ + +#ifdef CONFIG_MCA + if (MCA_bus) { + int slot = 0; + + /* + * Only find one card at a time. Subsequent calls + * will find others, however, proper multicard MCA + * probing and setup can't be done with the + * old-style Space.c init routines. -- ASF + */ + while (slot != MCA_NOTFOUND) { + int pos0, pos1; + + slot = mca_find_unused_adapter(0x628B, slot); + if (slot == MCA_NOTFOUND) + break; + + pos0 = mca_read_stored_pos(slot, 2); + pos1 = mca_read_stored_pos(slot, 3); + ioaddr = mca_iomap[pos1&0xf]; + + dev->irq = mca_irqmap[(pos1>>4)&0x7]; + + /* + * XXX: Transciever selection is done + * differently on the MCA version. + * How to get it to select something + * other than external/AUI is currently + * unknown. This code is just for looks. -- ASF + */ + if ((pos0 & 0x7) == 0x1) + dev->if_port = AUI; + else if ((pos0 & 0x7) == 0x5) { + if (pos1 & 0x80) + dev->if_port = BNC; + else + dev->if_port = TPE; + } + + mca_set_adapter_name(slot, "Intel EtherExpress 16 MCA"); + mca_set_adapter_procfn(slot, NULL, dev); + mca_mark_as_used(slot); + + break; + } + } +#endif if (ioaddr&0xfe00) return eexp_hw_probe(dev,ioaddr); else if (ioaddr) @@ -522,7 +583,9 @@ static void unstick_cu(struct net_device *dev) static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; +#ifdef CONFIG_SMP unsigned long flags; +#endif #if NET_DEBUG > 6 printk(KERN_DEBUG "%s: eexp_xmit()\n", dev->name); @@ -1010,8 +1073,10 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr) if (!dev->irq) dev->irq = irqmap[setupval>>13]; - dev->if_port = !(setupval & 0x1000) ? AUI : - eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC; + if (dev->if_port == 0xff) { + dev->if_port = !(setupval & 0x1000) ? AUI : + eexp_hw_readeeprom(ioaddr,5) & 0x1 ? TPE : BNC; + } buswidth = !((setupval & 0x400) >> 10); } diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index 483d94e45..922b28437 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -80,14 +80,11 @@ */ struct hydra_private { - u8 *hydra_base; - u8 *hydra_nic_base; u16 tx_page_start; u16 rx_page_start; u16 rx_page_stop; u16 next_pkt; struct net_device_stats stats; - unsigned int key; }; static int hydra_open(struct net_device *dev); @@ -159,52 +156,53 @@ static void memcpyw(u16 *dest, u16 *src, int len) int __init hydra_probe(struct net_device *dev) { - struct hydra_private *priv; - u32 board; - unsigned int key; - const struct ConfigDev *cd; + struct zorro_dev *z = NULL; int j; #ifdef HYDRA_DEBUG printk("hydra_probe(%x)\n", dev); #endif - if ((key = zorro_find(ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET, 0, 0))) - { - cd = zorro_get_board(key); - if((board = (u32) cd->cd_BoardAddr)) - { - for(j = 0; j < ETHER_ADDR_LEN; j++) - dev->dev_addr[j] = *((u8 *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j)); - - printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", - dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); - init_etherdev(dev, 0); - - dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL); - priv = (struct hydra_private *)dev->priv; - memset(priv, 0, sizeof(struct hydra_private)); - - priv->hydra_base = (u8 *) ZTWO_VADDR(board); - priv->hydra_nic_base = (u8 *) ZTWO_VADDR(board) + HYDRA_NIC_BASE; - priv->key = key; - - dev->open = &hydra_open; - dev->stop = &hydra_close; - dev->hard_start_xmit = &hydra_start_xmit; - dev->get_stats = &hydra_get_stats; + while ((z = zorro_find_device(ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET, z))) { + unsigned long board = z->resource.start; + unsigned long base_addr = board+HYDRA_NIC_BASE; + + if (!request_mem_region(base_addr, 0x20, "NS8390")) + continue; + if (!request_mem_region(board, 0x4000, "RAM")) { + release_mem_region(base_addr, 0x20); + continue; + } + strcpy(z->name, "Hydra Ethernet Card"); + + for(j = 0; j < ETHER_ADDR_LEN; j++) + dev->dev_addr[j] = *((u8 *)ZTWO_VADDR(board + HYDRA_ADDRPROM + 2*j)); + + printk("%s: hydra at 0x%08x, address %02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n", + dev->name, (int)board, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + init_etherdev(dev, 0); + + dev->priv = kmalloc(sizeof(struct hydra_private), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct hydra_private)); + + dev->base_addr = ZTWO_VADDR(base_addr); + dev->mem_start = ZTWO_VADDR(board); + dev->mem_end = dev->mem_start+0x4000; + + dev->open = &hydra_open; + dev->stop = &hydra_close; + dev->hard_start_xmit = &hydra_start_xmit; + dev->get_stats = &hydra_get_stats; #ifdef HAVE_MULTICAST - dev->set_multicast_list = &set_multicast_list; + dev->set_multicast_list = &set_multicast_list; #endif - - /* - * Cannot yet do multicast - */ - dev->flags&=~IFF_MULTICAST; - zorro_config_board(key, 0); - return(0); - } + + /* + * Cannot yet do multicast + */ + dev->flags&=~IFF_MULTICAST; + return(0); } return(-ENODEV); } @@ -213,7 +211,7 @@ int __init hydra_probe(struct net_device *dev) static int hydra_open(struct net_device *dev) { struct hydra_private *priv = (struct hydra_private *)dev->priv; - volatile u8 *nicbase = priv->hydra_nic_base; + volatile u8 *nicbase = (u8 *)dev->base_addr; int i; #ifdef HYDRA_DEBUG @@ -295,7 +293,7 @@ static int hydra_open(struct net_device *dev) static int hydra_close(struct net_device *dev) { struct hydra_private *priv = (struct hydra_private *)dev->priv; - volatile u8 *nicbase = priv->hydra_nic_base; + volatile u8 *nicbase = (u8 *)dev->base_addr; int n = 5000; dev->start = 0; @@ -340,7 +338,7 @@ static void hydra_interrupt(int irq, void *data, struct pt_regs *fp) dev->interrupt = 1; priv = (struct hydra_private *) dev->priv; - nicbase = (u8 *) priv->hydra_nic_base; + nicbase = (u8 *)dev->base_addr; /* select page 0 */ WRITE_REG(NIC_CR, CR_PAGE0 | CR_START | CR_NODMA); @@ -437,7 +435,7 @@ static void hydra_interrupt(int irq, void *data, struct pt_regs *fp) static int hydra_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct hydra_private *priv = (struct hydra_private *)dev->priv; - volatile u8 *nicbase = priv->hydra_nic_base; + volatile u8 *nicbase = (u8 *)dev->base_addr; int len, len1; /* Transmitter timeout, serious problems. */ @@ -491,16 +489,17 @@ static int hydra_start_xmit(struct sk_buff *skb, struct net_device *dev) /* make sure we've got an even number of bytes to copy to hydra's mem */ if(len & 1) len++; - if((u32)(priv->hydra_base + (priv->tx_page_start << 8)) < 0x80000000) - printk("weirdness: memcpyw(txbuf, skbdata, len): txbuf = 0x%x\n", (u_int)(priv->hydra_base+(priv->tx_page_start<<8))); + if((u32)(dev->mem_start + (priv->tx_page_start << 8)) < 0x80000000) + printk("weirdness: memcpyw(txbuf, skbdata, len): txbuf = 0x%x\n", (u_int)(dev->mem_start+(priv->tx_page_start<<8))); /* copy the packet data to the transmit buffer in the ethernet card RAM */ - memcpyw((u16 *)(priv->hydra_base + (priv->tx_page_start << 8)), + memcpyw((u16 *)(dev->mem_start + (priv->tx_page_start << 8)), (u16 *)skb->data, len); /* clear the unused space */ for(; len1<len; len1++) - (u16)*(priv->hydra_base + (priv->tx_page_start<<8) + len1) = 0; + (u16)*((u8 *)dev->mem_start + (priv->tx_page_start<<8) + len1) + = 0; dev_kfree_skb(skb); priv->stats.tx_packets++; @@ -536,7 +535,7 @@ static void __inline__ hydra_rx(struct net_device *dev, struct hydra_private *pr WRITE_REG(NIC_CR, CR_PAGE1 | CR_NODMA | CR_START); /* page 1 */ while(priv->next_pkt != READ_REG(NIC_CURR)) /* should read this only once? */ { - board_ram_ptr = (u16 *)(priv->hydra_base + (priv->next_pkt << 8)); + board_ram_ptr = (u16 *)(dev->mem_start + (priv->next_pkt << 8)); #ifdef HYDRA_DEBUG printk("next_pkt = 0x%x, board_ram_ptr = 0x%x\n", priv->next_pkt, board_ram_ptr); @@ -577,7 +576,7 @@ static void __inline__ hydra_rx(struct net_device *dev, struct hydra_private *pr len1 = ((priv->rx_page_stop - priv->next_pkt)<<8)-4; memcpyw((u16 *)skb_put(skb, len1), (u16 *)(board_ram_ptr+2), len1); - memcpyw((u16 *)skb_put(skb, pkt_len-len1), (u16 *)(priv->hydra_base+(priv->rx_page_start<<8)), pkt_len-len1); + memcpyw((u16 *)skb_put(skb, pkt_len-len1), (u16 *)(dev->mem_start+(priv->rx_page_start<<8)), pkt_len-len1); #ifdef HYDRA_DEBUG printk("wrapped packet: %d/%d bytes\n", len1, pkt_len-len1); @@ -638,7 +637,7 @@ static struct net_device_stats *hydra_get_stats(struct net_device *dev) { struct hydra_private *priv = (struct hydra_private *)dev->priv; #if 0 - u8 *board = priv->hydra_base; + u8 *board = (u8 *)dev->mem_start; short saved_addr; #endif @@ -651,7 +650,7 @@ static struct net_device_stats *hydra_get_stats(struct net_device *dev) static void set_multicast_list(struct net_device *dev, int num_addrs, void *addrs) { struct hydra_private *priv = (struct hydra_private *)dev->priv; - u8 *board = priv->hydra_base; + u8 *board = (u8 *)dev->mem_start; /* yes, this code is also waiting for someone to complete.. :) */ /* (personally i don't care about multicasts at all :) */ @@ -688,7 +687,8 @@ void cleanup_module(void) struct hydra_private *priv = (struct hydra_private *)hydra_dev.priv; unregister_netdev(&hydra_dev); - zorro_unconfig_board(priv->key, 0); + release_mem_region(ZTWO_PADDR(hydra_dev.base_addr), 0x20); + release_mem_region(ZTWO_PADDR(hydra_dev.mem_start), 0x4000); kfree(priv); } diff --git a/drivers/net/pcmcia/Config.in b/drivers/net/pcmcia/Config.in index be83dc205..243b5c896 100644 --- a/drivers/net/pcmcia/Config.in +++ b/drivers/net/pcmcia/Config.in @@ -31,8 +31,6 @@ if [ "$CONFIG_NET_PCMCIA" = "y" ]; then fi fi -endmenu - if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_3C574" = "y" -o \ "$CONFIG_PCMCIA_FMVJ18X" = "y" -o "$CONFIG_PCMCIA_PCNET" = "y" -o \ "$CONFIG_PCMCIA_NMCLAN" = "y" -o "$CONFIG_PCMCIA_SMC91C92" = "y" -o \ @@ -40,3 +38,5 @@ if [ "$CONFIG_PCMCIA_3C589" = "y" -o "$CONFIG_PCMCIA_3C574" = "y" -o \ "$CONFIG_PCMCIA_NETWAVE" = "y" -o "$CONFIG_PCMCIA_WAVELAN" = "y" ]; then define_bool CONFIG_PCMCIA_NETCARD y fi + +endmenu diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 471afb6d3..9e802387a 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -13,7 +13,7 @@ * This driver is for PCnet32 and PCnetPCI based ethercards */ -static const char *version = "pcnet32.c:v1.23ac 21.9.1999 tsbogend@alpha.franken.de\n"; +static const char *version = "pcnet32.c:v1.25kf 26.9.1999 tsbogend@alpha.franken.de\n"; #include <linux/config.h> #include <linux/module.h> @@ -46,12 +46,13 @@ static const char *version = "pcnet32.c:v1.23ac 21.9.1999 tsbogend@alpha.franken static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360, 0}; static int pcnet32_debug = 1; +static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ #ifdef MODULE static struct net_device *pcnet32_dev = NULL; #endif -static const int max_interrupt_work = 20; +static const int max_interrupt_work = 80; static const int rx_copybreak = 200; #define PORT_AUI 0x00 @@ -159,7 +160,12 @@ static int full_duplex[MAX_UNITS] = {0, }; * Michael Richard <mcr@solidum.com>) * added chip id for 79c973/975 (thanks to Zach Brown <zab@zabbo.net>) * v1.23 fixed small bug, when manual selecting MII speed/duplex - * v1.23ac Added SMP spinlocking - Alan Cox <alan@redhat.com> + * v1.24 Applied Thomas' patch to use TxStartPoint and thus decrease TxFIFO + * underflows. Added tx_start_pt module parameter. Increased + * TX_RING_SIZE from 16 to 32. Added #ifdef'd code to use DXSUFLO + * for FAST[+] chipsets. <kaf@fc.hp.com> + * v1.24ac Added SMP spinlocking - Alan Cox <alan@redhat.com> + * v1.25kf Added No Interrupt on successful Tx for some Tx's <kaf@fc.hp.com> */ @@ -170,7 +176,7 @@ static int full_duplex[MAX_UNITS] = {0, }; */ #ifndef PCNET32_LOG_TX_BUFFERS #define PCNET32_LOG_TX_BUFFERS 4 -#define PCNET32_LOG_RX_BUFFERS 4 +#define PCNET32_LOG_RX_BUFFERS 5 #endif #define TX_RING_SIZE (1 << (PCNET32_LOG_TX_BUFFERS)) @@ -260,12 +266,16 @@ struct pcnet32_private { struct pcnet32_access a; void *origmem; spinlock_t lock; /* Guard lock */ - int cur_rx, cur_tx; /* The next free ring entry */ - int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; char tx_full; int options; int shared_irq:1, /* shared irq possible */ + ltint:1, +#ifdef DO_DXSUFLO + dxsuflo:1, /* disable transmit stop on uflo */ +#endif full_duplex:1, /* full duplex possible */ mii:1; /* mii port available */ #ifdef MODULE @@ -304,6 +314,10 @@ static struct pcnet32_pci_id_info pcnet32_tbl[] = { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0, 0, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, pcnet32_probe1}, + { "AMD PCnetPCI series (IBM)", + PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000, + PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, + pcnet32_probe1}, { "AMD PCnetHome series", PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_PCNETHOME, 0, 0, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, @@ -453,8 +467,8 @@ int __init pcnet32_probe(void) int chip_idx; u16 sdid,svid; - pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &sdid); - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &svid); + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &svid); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &sdid); for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++) if ((pdev->vendor == pcnet32_tbl[chip_idx].vendor_id) && (pdev->device == pcnet32_tbl[chip_idx].device_id) && @@ -520,6 +534,10 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car { struct pcnet32_private *lp; int i,media,fdx = 0, mii = 0, fset = 0; +#ifdef DO_DXSUFLO + int dxsuflo = 0; +#endif + int ltint = 0; int chip_version; char *chipname; char *priv; @@ -562,6 +580,7 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car case 0x2623: chipname = "PCnet/FAST 79C971"; fdx = 1; mii = 1; fset = 1; + ltint = 1; break; case 0x2624: chipname = "PCnet/FAST+ 79C972"; @@ -610,7 +629,11 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car if(fset) { a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0800)); - a->write_csr(ioaddr, 80, a->read_csr(ioaddr, 80) | 0x0c00); + a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); +#ifdef DO_DXSUFLO + dxsuflo = 1; +#endif + ltint = 1; } dev = init_etherdev(NULL, 0); @@ -624,6 +647,29 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i)); + if (((chip_version + 1) & 0xfffe) == 0x2624) { /* Version 0x2623 or 0x2624 */ + i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */ + printk("\n tx_start_pt(0x%04x):",i); + switch(i>>10) { + case 0: printk(" 20 bytes,"); break; + case 1: printk(" 64 bytes,"); break; + case 2: printk(" 128 bytes,"); break; + case 3: printk("~220 bytes,"); break; + } + i = a->read_bcr(ioaddr, 18); /* Check Burst/Bus control */ + printk(" BCR18(%x):",i&0xffff); + if (i & (1<<5)) printk("BurstWrEn "); + if (i & (1<<6)) printk("BurstRdEn "); + if (i & (1<<7)) printk("DWordIO "); + if (i & (1<<11)) printk("NoUFlow "); + i = a->read_bcr(ioaddr, 25); + printk("\n SRAMSIZE=0x%04x,",i<<8); + i = a->read_bcr(ioaddr, 26); + printk(" SRAM_BND=0x%04x,",i<<8); + i = a->read_bcr(ioaddr, 27); + if (i & (1<<14)) printk("LowLatRx,"); + } + dev->base_addr = ioaddr; request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname); @@ -654,6 +700,10 @@ pcnet32_probe1(unsigned long ioaddr, unsigned char irq_line, int shared, int car lp->name = chipname; lp->shared_irq = shared; lp->full_duplex = fdx; +#ifdef DO_DXSUFLO + lp->dxsuflo = dxsuflo; +#endif + lp->ltint = ltint; lp->mii = mii; if (options[card_idx] > sizeof (options_mapping)) lp->options = PORT_ASEL; @@ -795,7 +845,20 @@ pcnet32_open(struct net_device *dev) val |= 0x08; lp->a.write_bcr (ioaddr, 32, val); } - + +#ifdef DO_DXSUFLO + if (lp->dxsuflo) { /* Disable transmit stop on underflow */ + val = lp->a.read_csr (ioaddr, 3); + val |= 0x40; + lp->a.write_csr (ioaddr, 3, val); + } +#endif + if (lp->ltint) { /* Enable TxDone-intr inhibitor */ + val = lp->a.read_csr (ioaddr, 5); + val |= (1<<14); + lp->a.write_csr (ioaddr, 5, val); + } + lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7); lp->init_block.filter[0] = 0x00000000; lp->init_block.filter[1] = 0x00000000; @@ -925,6 +988,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; unsigned int ioaddr = dev->base_addr; + u16 status; int entry; unsigned long flags; @@ -973,11 +1037,28 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) } spin_lock_irqsave(&lp->lock, flags); - /* Fill in a Tx ring entry */ + /* Default status -- will not enable Successful-TxDone + * interrupt when that option is available to us. + */ + status = 0x8300; + if ((lp->ltint) && + ((lp->cur_tx - lp->dirty_tx == TX_RING_SIZE/2) || + (lp->cur_tx - lp->dirty_tx >= TX_RING_SIZE-2))) + { + /* Enable Successful-TxDone interrupt if we have + * 1/2 of, or nearly all of, our ring buffer Tx'd + * but not yet cleaned up. Thus, most of the time, + * we will not enable Successful-TxDone interrupts. + */ + status = 0x9300; + } + + /* Fill in a Tx ring entry */ + /* Mask to ring buffer boundary. */ entry = lp->cur_tx & TX_RING_MOD_MASK; - + /* Caution: the write order is important here, set the base address with the "ownership" bits last. */ @@ -987,7 +1068,7 @@ pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) lp->tx_skbuff[entry] = skb; lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data)); - lp->tx_ring[entry].status = le16_to_cpu(0x8300); + lp->tx_ring[entry].status = le16_to_cpu(status); dma_cache_wback_inv((void *)skb->data, (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len); @@ -1049,7 +1130,7 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) pcnet32_rx(dev); if (csr0 & 0x0200) { /* Tx-done interrupt */ - int dirty_tx = lp->dirty_tx; + unsigned int dirty_tx = lp->dirty_tx; while (dirty_tx < lp->cur_tx) { int entry = dirty_tx & TX_RING_MOD_MASK; @@ -1067,14 +1148,27 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) if (err_status & 0x04000000) lp->stats.tx_aborted_errors++; if (err_status & 0x08000000) lp->stats.tx_carrier_errors++; if (err_status & 0x10000000) lp->stats.tx_window_errors++; - if (err_status & 0x40000000) { +#ifndef DO_DXSUFLO + if (err_status & 0x40000000) { + lp->stats.tx_fifo_errors++; /* Ackk! On FIFO errors the Tx unit is turned off! */ + /* Remove this verbosity later! */ + printk("%s: Tx FIFO error! CSR0=%4.4x\n", + dev->name, csr0); + must_restart = 1; + } +#else + if (err_status & 0x40000000) { lp->stats.tx_fifo_errors++; - /* Remove this verbosity later! */ - printk("%s: Tx FIFO error! Status %4.4x.\n", - dev->name, csr0); - must_restart = 1; - } + if (! lp->dxsuflo) { /* If controller doesn't recover ... */ + /* Ackk! On FIFO errors the Tx unit is turned off! */ + /* Remove this verbosity later! */ + printk("%s: Tx FIFO error! CSR0=%4.4x\n", + dev->name, csr0); + must_restart = 1; + } + } +#endif } else { if (status & 0x1800) lp->stats.collisions++; @@ -1413,18 +1507,22 @@ static int pcnet32_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) MODULE_PARM(debug, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(tx_start_pt, "i"); MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); /* An additional parameter that may be passed in... */ static int debug = -1; +static int tx_start_pt = -1; int init_module(void) { if (debug > 0) pcnet32_debug = debug; + if ((tx_start_pt >= 0) && (tx_start_pt <= 3)) + tx_start = tx_start_pt; pcnet32_dev = NULL; return pcnet32_probe(); diff --git a/drivers/net/setup.c b/drivers/net/setup.c index 601617f79..2eab3d4b7 100644 --- a/drivers/net/setup.c +++ b/drivers/net/setup.c @@ -48,6 +48,7 @@ extern int rcpci_probe(void); extern int rr_hippi_probe(void); extern int rtl8139_probe(void); extern int sdla_setup(void); +extern int sdla_c_setup(void); extern int sis900_probe(void); extern int skge_probe(void); extern int sparc_lance_probe(void); @@ -57,6 +58,10 @@ extern int tulip_probe(void); extern int via_rhine_probe(void); extern int yellowfin_probe(void); +extern int abyss_probe(void); +extern int madgemc_probe(void); +extern int tms_pci_probe(void); + /* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is tring of 9 zeros. */ #define __PAD6 "\0\0\0\0\0\0\0\0\0" #define __PAD5 __PAD6 "\0" @@ -94,7 +99,7 @@ struct net_probe pci_probes[] __initdata = { {dlci_setup, 0}, #endif #if defined(CONFIG_SDLA) - {sdla_setup, 0}, + {sdla_c_setup, 0}, #endif #if defined(CONFIG_LAPBETHER) {lapbeth_init, 0}, @@ -249,7 +254,19 @@ struct net_probe pci_probes[] __initdata = { #ifdef CONFIG_YAM {yam_init, 0}, #endif /* CONFIG_YAM */ - + +/* + * Token Ring Drivers + */ +#ifdef CONFIG_ABYSS + {abyss_probe, 0}, +#endif +#ifdef CONFIG_MADGEMC + {madgemc_probe, 0}, +#endif +#ifdef CONFIG_TMSPCI + {tms_pci_probe, 0}, +#endif {NULL, 0}, }; diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 5c5b13c06..10e466a5d 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -1165,11 +1165,11 @@ static int __init bigmac_ether_init(struct net_device *dev, struct sbus_dev *qec bigmac_stop(bp); /* Allocate transmit/receive descriptor DVMA block. */ - bp->bmac_block = sbus_alloc_consistant(bp->bigmac_sdev, + bp->bmac_block = sbus_alloc_consistent(bp->bigmac_sdev, PAGE_SIZE, &bp->bblock_dvma); if (bp->bmac_block == NULL || bp->bblock_dvma == 0) { - printk(KERN_ERR "BIGMAC: Cannot allocate consistant DMA.\n"); + printk(KERN_ERR "BIGMAC: Cannot allocate consistent DMA.\n"); goto fail_and_cleanup; } @@ -1220,7 +1220,7 @@ fail_and_cleanup: sbus_iounmap(bp->tregs, TCVR_REG_SIZE); if (bp->bmac_block) - sbus_free_consistant(bp->bigmac_sdev, + sbus_free_consistent(bp->bigmac_sdev, PAGE_SIZE, bp->bmac_block, bp->bblock_dvma); @@ -1301,7 +1301,7 @@ cleanup_module(void) sbus_iounmap(bp->creg, CREG_REG_SIZE); sbus_iounmap(bp->bregs, BMAC_REG_SIZE); sbus_iounmap(bp->tregs, TCVR_REG_SIZE); - sbus_free_consistant(bp->bigmac_sdev, + sbus_free_consistent(bp->bigmac_sdev, PAGE_SIZE, bp->bmac_block, bp->bblock_dvma); diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index e18ce36a3..eb76a9fee 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -207,42 +207,6 @@ static u32 pci_hme_read_desc32(u32 *p) return cpu_to_le32(*p); } -/* XXX Convert these to direct function hookup once new - * XXX PCI dvma interfaces are propagated and in use everywhere. - */ -static u32 pci_hme_dma_map(void *device, void *ptr, long size) -{ -#if 1 - return virt_to_bus(ptr); -#else - struct pci_dev *pdev = device; - - return pci_map_single(pdev, ptr, size); -#endif -} - -static void pci_hme_dma_unmap(void *device, u32 dma_addr, long size) -{ -#if 1 - return; -#else - struct pci_dev *pdev = device; - - pci_unmap_single(pdev, dma_addr, size); -#endif -} - -static void pci_hme_dma_sync(void *device, u32 dma_addr, long size) -{ -#if 1 - return; -#else - struct pci_dev *pdev = device; - - pci_dma_sync_single(pdev, dma_addr, size); -#endif -} - #define hme_write32(__hp, __reg, __val) \ ((__hp)->write32((__reg), (__val))) #define hme_read32(__hp, __reg) \ @@ -296,21 +260,12 @@ do { (__txd)->tx_addr = cpu_to_le32(__addr); \ (__txd)->tx_flags = cpu_to_le32(__flags); \ } while(0) #define hme_read_desc32(__hp, __p) cpu_to_le32(*(__p)) -#if 0 /* XXX Once new PCI interfaces are in place... XXX */ #define hme_dma_map(__hp, __ptr, __size) \ pci_map_single((__hp)->happy_dev, (__ptr), (__size)) #define hme_dma_unmap(__hp, __addr, __size) \ pci_unmap_single((__hp)->happy_dev, (__addr), (__size)) #define hme_dma_sync(__hp, __addr, __size) \ pci_dma_sync_single((__hp)->happy_dev, (__addr), (__size)) -#else -#define hme_dma_map(__hp, __ptr, __size) \ - (virt_to_bus(__ptr)) -#define hme_dma_unmap(__hp, __addr, __size) \ - do { } while(0) -#define hme_dma_sync(__hp, __addr, __size) \ - do { } while(0) -#endif #endif #endif @@ -2663,7 +2618,7 @@ static int __init happy_meal_sbus_init(struct net_device *dev, hp->happy_bursts = prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0x00); - hp->happy_block = sbus_alloc_consistant(hp->happy_dev, + hp->happy_block = sbus_alloc_consistent(hp->happy_dev, PAGE_SIZE, &hp->hblock_dvma); @@ -2835,20 +2790,14 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd /* Assume PCI happy meals can handle all burst sizes. */ hp->happy_bursts = DMA_BURSTBITS; - hp->happy_block = (struct hmeal_init_block *) get_free_page(GFP_ATOMIC); + hp->happy_block = (struct hmeal_init_block *) + pci_alloc_consistent(pdev, PAGE_SIZE, &hp->hblock_dvma); + if (!hp->happy_block) { printk(KERN_ERR "happymeal(PCI): Cannot get hme init block.\n"); return ENODEV; } - hp->hblock_dvma = (u32) virt_to_bus(hp->happy_block); -#ifndef __sparc_v9__ - /* - * P3: Dirty trick to get uncacheable memory as we have no dma_sync. - */ - hp->happy_block = ioremap(virt_to_phys(hp->happy_block), PAGE_SIZE); -#endif - hp->linkcheck = 0; hp->timer_state = asleep; hp->timer_ticks = 0; @@ -2870,9 +2819,9 @@ static int __init happy_meal_pci_init(struct net_device *dev, struct pci_dev *pd hp->read_desc32 = pci_hme_read_desc32; hp->write_txd = pci_hme_write_txd; hp->write_rxd = pci_hme_write_rxd; - hp->dma_map = pci_hme_dma_map; - hp->dma_unmap = pci_hme_dma_unmap; - hp->dma_sync = pci_hme_dma_sync; + hp->dma_map = (u32 (*)(void *, void *, long))pci_map_single; + hp->dma_unmap = (void (*)(void *, u32, long))pci_unmap_single; + hp->dma_sync = (void (*)(void *, u32, long))pci_dma_sync_single; hp->read32 = pci_hme_read32; hp->write32 = pci_hme_write32; #endif @@ -3011,12 +2960,20 @@ cleanup_module(void) sbus_iounmap(hp->erxregs, ERX_REG_SIZE); sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE); sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE); - sbus_free_consistant(hp->happy_dev, + sbus_free_consistent(hp->happy_dev, PAGE_SIZE, hp->happy_block, hp->hblock_dvma); } #endif +#ifdef CONFIG_PCI + if ((hp->happy_flags & HFLAG_PCI)) { + pci_free_consistent(hp->happy_dev, + PAGE_SIZE, + hp->happy_block, + hp->hblock_dvma); + } +#endif unregister_netdev(hp->dev); kfree(hp->dev); root_happy_dev = next; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 44548e437..3c499ba38 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -1305,7 +1305,7 @@ static void lance_free_hwresources(struct lance_private *lp) sbus_iounmap((unsigned long)lp->init_block, sizeof(struct lance_init_block)); } else { - sbus_free_consistant(lp->sdev, + sbus_free_consistent(lp->sdev, sizeof(struct lance_init_block), (void *)lp->init_block, lp->init_block_dvma); @@ -1375,11 +1375,11 @@ static int __init sparc_lance_init(struct net_device *dev, lp->tx = lance_tx_pio; } else { lp->init_block = (volatile struct lance_init_block *) - sbus_alloc_consistant(sdev, sizeof(struct lance_init_block), + sbus_alloc_consistent(sdev, sizeof(struct lance_init_block), &lp->init_block_dvma); if (lp->init_block == NULL || lp->init_block_dvma == 0) { - printk(KERN_ERR "%s: Cannot allocate consistant DMA memory.\n", + printk(KERN_ERR "%s: Cannot allocate consistent DMA memory.\n", dev->name); goto fail; } diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index 63208eb47..2a170a0a6 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -833,10 +833,10 @@ static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev) goto qec_free_devs; } - qeps[i]->qe_block = sbus_alloc_consistant(qesdevs[i], + qeps[i]->qe_block = sbus_alloc_consistent(qesdevs[i], PAGE_SIZE, &qeps[i]->qblock_dvma); - qeps[i]->buffers = sbus_alloc_consistant(qesdevs[i], + qeps[i]->buffers = sbus_alloc_consistent(qesdevs[i], sizeof(struct sunqe_buffers), &qeps[i]->buffers_dvma); if (qeps[i]->qe_block == NULL || @@ -907,12 +907,12 @@ qec_free_devs: if (qe->mregs) sbus_iounmap(qe->mregs, MREGS_REG_SIZE); if (qe->qe_block != NULL) - sbus_free_consistant(qe->qe_sdev, + sbus_free_consistent(qe->qe_sdev, PAGE_SIZE, qe->qe_block, qe->qblock_dvma); if (qe->buffers != NULL) - sbus_free_consistant(qe->qe_sdev, + sbus_free_consistent(qe->qe_sdev, sizeof(struct sunqe_buffers), qe->buffers, qe->buffers_dvma); @@ -1006,11 +1006,11 @@ cleanup_module(void) unregister_netdev(root_qec_dev->qes[i]->dev); sbus_iounmap(root_qec_dev->qes[i]->qcregs, CREG_REG_SIZE); sbus_iounmap(root_qec_dev->qes[i]->mregs, MREGS_REG_SIZE); - sbus_free_consistant(root_qec_dev->qes[i]->qe_sdev, + sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev, PAGE_SIZE, root_qec_dev->qes[i]->qe_block, root_qec_dev->qes[i]->qblock_dvma); - sbus_free_consistant(root_qec_dev->qes[i]->qe_sdev, + sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev, sizeof(struct sunqe_buffers), root_qec_dev->qes[i]->buffers, root_qec_dev->qes[i]->buffers_dvma); diff --git a/drivers/net/tokenring/Config.in b/drivers/net/tokenring/Config.in index a862c247b..b7e67fbad 100644 --- a/drivers/net/tokenring/Config.in +++ b/drivers/net/tokenring/Config.in @@ -6,11 +6,16 @@ mainmenu_option next_comment comment 'Token Ring driver support' bool 'Token Ring driver support' CONFIG_TR -if [ "$CONFIG_TR" = "y" ]; then - tristate ' IBM Tropic chipset based adapter support' CONFIG_IBMTR - tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL - tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR - tristate ' SMC ISA adapter support' CONFIG_SMCTR +if [ "$CONFIG_TR" != "n" ]; then + dep_tristate ' IBM Tropic chipset based adapter support' CONFIG_IBMTR $CONFIG_TR + dep_tristate ' IBM Olympic chipset PCI adapter support' CONFIG_IBMOL $CONFIG_TR + dep_tristate ' Generic TMS380 Token Ring ISA/PCI adapter support' CONFIG_TMS380TR $CONFIG_TR + if [ "$CONFIG_TMS380TR" != "n" ]; then + dep_tristate ' Generic TMS380 PCI support' CONFIG_TMSPCI $CONFIG_TMS380TR + dep_tristate ' Madge Smart 16/4 PCI Mk2 support' CONFIG_ABYSS $CONFIG_TMS380TR + dep_tristate ' Madge Smart 16/4 Ringnode MicroChannel' CONFIG_MADGEMC $CONFIG_TMS380TR + fi + dep_tristate ' SMC ISA/MCA adapter support' CONFIG_SMCTR $CONFIG_TR fi endmenu diff --git a/drivers/net/tokenring/Makefile b/drivers/net/tokenring/Makefile index 72629233b..65dfefc70 100644 --- a/drivers/net/tokenring/Makefile +++ b/drivers/net/tokenring/Makefile @@ -41,9 +41,27 @@ endif ifeq ($(CONFIG_TMS380TR),y) L_OBJS += tms380tr.o + ifeq ($(CONFIG_ABYSS),y) + L_OBJS += abyss.o + endif + ifeq ($(CONFIG_MADGEMC),y) + L_OBJS += madgemc.o + endif + ifeq ($(CONFIG_TMSPCI),y) + L_OBJS += tmspci.o + endif else ifeq ($(CONFIG_TMS380TR),m) M_OBJS += tms380tr.o + ifeq ($(CONFIG_ABYSS),m) + M_OBJS += abyss.o + endif + ifeq ($(CONFIG_MADGEMC),m) + M_OBJS += madgemc.o + endif + ifeq ($(CONFIG_TMSPCI),m) + M_OBJS += tmspci.o + endif endif endif diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c new file mode 100644 index 000000000..724847af2 --- /dev/null +++ b/drivers/net/tokenring/abyss.c @@ -0,0 +1,512 @@ +/* + * abyss.c: Network driver for the Madge Smart 16/4 PCI Mk2 token ring card. + * + * Written 1999-2000 by Adam Fritzler + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * This driver module supports the following cards: + * - Madge Smart 16/4 PCI Mk2 + * + * Maintainer(s): + * AF Adam Fritzler mid@auk.cx + * + * Modification History: + * 30-Dec-99 AF Split off from the tms380tr driver. + * 22-Jan-00 AF Updated to use indirect read/writes + * + * + * TODO: + * 1. See if we can use MMIO instead of inb/outb/inw/outw + * 2. Add support for Mk1 (has AT24 attached to the PCI + * config registers) + * + */ +static const char *version = "abyss.c: v1.01 22/01/2000 by Adam Fritzler\n"; + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> + +#include <linux/netdevice.h> +#include <linux/trdevice.h> +#include "tms380tr.h" +#include "abyss.h" /* Madge-specific constants */ + +#define ABYSS_IO_EXTENT 64 + +int abyss_probe(void); +static int abyss_open(struct net_device *dev); +static int abyss_close(struct net_device *dev); +static void abyss_enable(struct net_device *dev); +static int abyss_chipset_init(struct net_device *dev); +static void abyss_read_eeprom(struct net_device *dev); +static unsigned short abyss_setnselout_pins(struct net_device *dev); + +void at24_writedatabyte(unsigned long regaddr, unsigned char byte); +int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr); +int at24_sendcmd(unsigned long regaddr, unsigned char cmd); +unsigned char at24_readdatabit(unsigned long regaddr); +unsigned char at24_readdatabyte(unsigned long regaddr); +int at24_waitforack(unsigned long regaddr); +int at24_waitfornack(unsigned long regaddr); +void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data); +void at24_start(unsigned long regaddr); +void at24_stop(unsigned long regaddr); +unsigned char at24_readb(unsigned long regaddr, unsigned char addr); + +static unsigned short abyss_sifreadb(struct net_device *dev, unsigned short reg) +{ + return inb(dev->base_addr + reg); +} + +static unsigned short abyss_sifreadw(struct net_device *dev, unsigned short reg) +{ + return inw(dev->base_addr + reg); +} + +static void abyss_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) +{ + outb(val, dev->base_addr + reg); +} + +static void abyss_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) +{ + outw(val, dev->base_addr + reg); +} + +struct tms_abyss_card { + struct net_device *dev; + struct pci_dev *pci_dev; + struct tms_abyss_card *next; +}; +static struct tms_abyss_card *abyss_card_list = NULL; + +int __init abyss_probe(void) +{ + static int versionprinted = 0; + struct pci_dev *pdev = NULL ; + struct net_device *dev; + struct net_local *tp; + int i; + + if (!pci_present()) + return (-1); /* No PCI present. */ + + while ( (pdev=pci_find_class(PCI_CLASS_NETWORK_TOKEN_RING<<8, pdev))) { + unsigned int pci_irq_line; + unsigned long pci_ioaddr; + struct tms_abyss_card *card; + + /* We only support Madge Smart 16/4 PCI Mk2 (Abyss) cards */ + if ( (pdev->vendor != PCI_VENDOR_ID_MADGE) || + (pdev->device != PCI_DEVICE_ID_MADGE_MK2) ) + continue; + + if (versionprinted++ == 0) + printk("%s", version); + + pci_enable_device(pdev); + + /* Remove I/O space marker in bit 0. */ + pci_irq_line = pdev->irq; + pci_ioaddr = pdev->resource[0].start ; + + if(check_region(pci_ioaddr, ABYSS_IO_EXTENT)) + continue; + + /* At this point we have found a valid card. */ + + dev = init_trdev(NULL, 0); + + request_region(pci_ioaddr, ABYSS_IO_EXTENT, "abyss"); + if(request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ, + "abyss", dev)) { + release_region(pci_ioaddr, ABYSS_IO_EXTENT) ; + continue; /*return (-ENODEV);*/ /* continue; ?? */ + } + + /* + if (load_tms380_module("abyss.c")) { + return 0; + } + */ + + pci_ioaddr &= ~3 ; + dev->base_addr = pci_ioaddr; + dev->irq = pci_irq_line; + dev->dma = 0; + + printk("%s: Madge Smart 16/4 PCI Mk2 (Abyss)\n", dev->name); + printk("%s: IO: %#4lx IRQ: %d\n", + dev->name, pci_ioaddr, dev->irq); + /* + * The TMS SIF registers lay 0x10 above the card base address. + */ + dev->base_addr += 0x10; + + if (tmsdev_init(dev)) { + printk("%s: unable to get memory for dev->priv.\n", + dev->name); + return 0; + } + + abyss_read_eeprom(dev); + + printk("%s: Ring Station Address: ", dev->name); + printk("%2.2x", dev->dev_addr[0]); + for (i = 1; i < 6; i++) + printk(":%2.2x", dev->dev_addr[i]); + printk("\n"); + + tp = (struct net_local *)dev->priv; + tp->dmalimit = 0; /* XXX: should be the max PCI32 DMA max */ + tp->setnselout = abyss_setnselout_pins; + tp->sifreadb = abyss_sifreadb; + tp->sifreadw = abyss_sifreadw; + tp->sifwriteb = abyss_sifwriteb; + tp->sifwritew = abyss_sifwritew; + + memcpy(tp->ProductID, "Madge PCI 16/4 Mk2", PROD_ID_SIZE + 1); + + dev->open = abyss_open; + dev->stop = abyss_close; + + if (register_trdev(dev) == 0) { + /* Enlist in the card list */ + card = kmalloc(sizeof(struct tms_abyss_card), + GFP_KERNEL); + card->next = abyss_card_list; + abyss_card_list = card; + card->dev = dev; + card->pci_dev = pdev; + } else { + printk("abyss: register_trdev() returned non-zero.\n"); + kfree(dev->priv); + kfree(dev); + return -1; + } + } + + if (abyss_card_list) + return 0; + return (-1); +} + +unsigned short abyss_setnselout_pins(struct net_device *dev) +{ + unsigned short val = 0; + struct net_local *tp = (struct net_local *)dev->priv; + + if(tp->DataRate == SPEED_4) + val |= 0x01; /* Set 4Mbps */ + else + val |= 0x00; /* Set 16Mbps */ + + return val; +} + +/* + * The following Madge boards should use this code: + * - Smart 16/4 PCI Mk2 (Abyss) + * - Smart 16/4 PCI Mk1 (PCI T) + * - Smart 16/4 Client Plus PnP (Big Apple) + * - Smart 16/4 Cardbus Mk2 + * + * These access an Atmel AT24 SEEPROM using their glue chip registers. + * + */ +void at24_writedatabyte(unsigned long regaddr, unsigned char byte) +{ + int i; + + for (i = 0; i < 8; i++) { + at24_setlines(regaddr, 0, (byte >> (7-i))&0x01); + at24_setlines(regaddr, 1, (byte >> (7-i))&0x01); + at24_setlines(regaddr, 0, (byte >> (7-i))&0x01); + } +} + +int at24_sendfullcmd(unsigned long regaddr, unsigned char cmd, unsigned char addr) +{ + if (at24_sendcmd(regaddr, cmd)) { + at24_writedatabyte(regaddr, addr); + return at24_waitforack(regaddr); + } + return 0; +} + +int at24_sendcmd(unsigned long regaddr, unsigned char cmd) +{ + int i; + + for (i = 0; i < 10; i++) { + at24_start(regaddr); + at24_writedatabyte(regaddr, cmd); + if (at24_waitforack(regaddr)) + return 1; + } + return 0; +} + +unsigned char at24_readdatabit(unsigned long regaddr) +{ + unsigned char val; + + at24_setlines(regaddr, 0, 1); + at24_setlines(regaddr, 1, 1); + val = (inb(regaddr) & AT24_DATA)?1:0; + at24_setlines(regaddr, 1, 1); + at24_setlines(regaddr, 0, 1); + return val; +} + +unsigned char at24_readdatabyte(unsigned long regaddr) +{ + unsigned char data = 0; + int i; + + for (i = 0; i < 8; i++) { + data <<= 1; + data |= at24_readdatabit(regaddr); + } + + return data; +} + +int at24_waitforack(unsigned long regaddr) +{ + int i; + + for (i = 0; i < 10; i++) { + if ((at24_readdatabit(regaddr) & 0x01) == 0x00) + return 1; + } + return 0; +} + +int at24_waitfornack(unsigned long regaddr) +{ + int i; + for (i = 0; i < 10; i++) { + if ((at24_readdatabit(regaddr) & 0x01) == 0x01) + return 1; + } + return 0; +} + +void at24_setlines(unsigned long regaddr, unsigned char clock, unsigned char data) +{ + unsigned char val; + val = AT24_ENABLE; + if (clock) + val |= AT24_CLOCK; + if (data) + val |= AT24_DATA; + + outb(val, regaddr); + tms380tr_wait(20); /* Very necessary. */ +} + +void at24_start(unsigned long regaddr) +{ + at24_setlines(regaddr, 0, 1); + at24_setlines(regaddr, 1, 1); + at24_setlines(regaddr, 1, 0); + at24_setlines(regaddr, 0, 1); + return; +} + +void at24_stop(unsigned long regaddr) +{ + at24_setlines(regaddr, 0, 0); + at24_setlines(regaddr, 1, 0); + at24_setlines(regaddr, 1, 1); + at24_setlines(regaddr, 0, 1); + return; +} + +unsigned char at24_readb(unsigned long regaddr, unsigned char addr) +{ + unsigned char data = 0xff; + + if (at24_sendfullcmd(regaddr, AT24_WRITE, addr)) { + if (at24_sendcmd(regaddr, AT24_READ)) { + data = at24_readdatabyte(regaddr); + if (!at24_waitfornack(regaddr)) + data = 0xff; + } + } + return data; +} + + +/* + * Enable basic functions of the Madge chipset needed + * for initialization. + */ +static void abyss_enable(struct net_device *dev) +{ + unsigned char reset_reg; + unsigned long ioaddr; + + ioaddr = dev->base_addr; + reset_reg = inb(ioaddr + PCIBM2_RESET_REG); + reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + tms380tr_wait(100); + return; +} + +/* + * Enable the functions of the Madge chipset needed for + * full working order. + */ +static int abyss_chipset_init(struct net_device *dev) +{ + unsigned char reset_reg; + unsigned long ioaddr; + + ioaddr = dev->base_addr; + + reset_reg = inb(ioaddr + PCIBM2_RESET_REG); + + reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + + reset_reg &= ~(PCIBM2_RESET_REG_CHIP_NRES | + PCIBM2_RESET_REG_FIFO_NRES | + PCIBM2_RESET_REG_SIF_NRES); + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + + tms380tr_wait(100); + + reset_reg |= PCIBM2_RESET_REG_CHIP_NRES; + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + + reset_reg |= PCIBM2_RESET_REG_SIF_NRES; + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + + reset_reg |= PCIBM2_RESET_REG_FIFO_NRES; + outb(reset_reg, ioaddr + PCIBM2_RESET_REG); + + outb(PCIBM2_INT_CONTROL_REG_SINTEN | + PCIBM2_INT_CONTROL_REG_PCI_ERR_ENABLE, + ioaddr + PCIBM2_INT_CONTROL_REG); + + outb(30, ioaddr + PCIBM2_FIFO_THRESHOLD); + + return 0; +} + +void abyss_chipset_close(struct net_device *dev) +{ + unsigned long ioaddr; + + ioaddr = dev->base_addr; + outb(0, ioaddr + PCIBM2_RESET_REG); + + return; +} + +/* + * Read configuration data from the AT24 SEEPROM on Madge cards. + * + */ +static void abyss_read_eeprom(struct net_device *dev) +{ + struct net_local *tp; + unsigned long ioaddr; + unsigned short val; + int i; + + tp = (struct net_local *)dev->priv; + ioaddr = dev->base_addr; + + /* Must enable glue chip first */ + abyss_enable(dev); + + val = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, + PCIBM2_SEEPROM_RING_SPEED); + tp->DataRate = val?SPEED_4:SPEED_16; /* set open speed */ + printk("%s: SEEPROM: ring speed: %dMb/sec\n", dev->name, tp->DataRate); + + val = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, + PCIBM2_SEEPROM_RAM_SIZE) * 128; + printk("%s: SEEPROM: adapter RAM: %dkb\n", dev->name, val); + + dev->addr_len = 6; + for (i = 0; i < 6; i++) + dev->dev_addr[i] = at24_readb(ioaddr + PCIBM2_SEEPROM_REG, + PCIBM2_SEEPROM_BIA+i); + + return; +} + +static int abyss_open(struct net_device *dev) +{ + abyss_chipset_init(dev); + tms380tr_open(dev); + MOD_INC_USE_COUNT; + return 0; +} + +static int abyss_close(struct net_device *dev) +{ + tms380tr_close(dev); + abyss_chipset_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef MODULE + +int init_module(void) +{ + /* Probe for cards. */ + if (abyss_probe()) { + printk(KERN_NOTICE "abyss.c: No cards found.\n"); + } + /* lock_tms380_module(); */ + return (0); +} + +void cleanup_module(void) +{ + struct net_device *dev; + struct tms_abyss_card *this_card; + + while (abyss_card_list) { + dev = abyss_card_list->dev; + unregister_netdev(dev); + release_region(dev->base_addr-0x10, ABYSS_IO_EXTENT); + free_irq(dev->irq, dev); + kfree(dev->priv); + kfree(dev); + this_card = abyss_card_list; + abyss_card_list = this_card->next; + kfree(this_card); + } + /* unlock_tms380_module(); */ +} +#endif /* MODULE */ + + +/* + * Local variables: + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c abyss.c" + * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c abyss.c" + * c-set-style "K&R" + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/tokenring/abyss.h b/drivers/net/tokenring/abyss.h new file mode 100644 index 000000000..0ee6e4f08 --- /dev/null +++ b/drivers/net/tokenring/abyss.h @@ -0,0 +1,58 @@ +/* + * abyss.h: Header for the abyss tms380tr module + * + * Authors: + * - Adam Fritzler <mid@auk.cx> + */ + +#ifndef __LINUX_MADGETR_H +#define __LINUX_MADGETR_H + +#ifdef __KERNEL__ + +/* + * For Madge Smart 16/4 PCI Mk2. Since we increment the base address + * to get everything correct for the TMS SIF, we do these as negatives + * as they fall below the SIF in addressing. + */ +#define PCIBM2_INT_STATUS_REG ((short)-15)/* 0x01 */ +#define PCIBM2_INT_CONTROL_REG ((short)-14)/* 0x02 */ +#define PCIBM2_RESET_REG ((short)-12)/* 0x04 */ +#define PCIBM2_SEEPROM_REG ((short)-9) /* 0x07 */ + +#define PCIBM2_INT_CONTROL_REG_SINTEN 0x02 +#define PCIBM2_INT_CONTROL_REG_PCI_ERR_ENABLE 0x80 +#define PCIBM2_INT_STATUS_REG_PCI_ERR 0x80 + +#define PCIBM2_RESET_REG_CHIP_NRES 0x01 +#define PCIBM2_RESET_REG_FIFO_NRES 0x02 +#define PCIBM2_RESET_REG_SIF_NRES 0x04 + +#define PCIBM2_FIFO_THRESHOLD 0x21 +#define PCIBM2_BURST_LENGTH 0x22 + +/* + * Bits in PCIBM2_SEEPROM_REG. + */ +#define AT24_ENABLE 0x04 +#define AT24_DATA 0x02 +#define AT24_CLOCK 0x01 + +/* + * AT24 Commands. + */ +#define AT24_WRITE 0xA0 +#define AT24_READ 0xA1 + +/* + * Addresses in AT24 SEEPROM. + */ +#define PCIBM2_SEEPROM_BIA 0x12 +#define PCIBM2_SEEPROM_RING_SPEED 0x18 +#define PCIBM2_SEEPROM_RAM_SIZE 0x1A +#define PCIBM2_SEEPROM_HWF1 0x1C +#define PCIBM2_SEEPROM_HWF2 0x1E + + +#endif /* __KERNEL__ */ +#endif /* __LINUX_MADGETR_H */ diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c new file mode 100644 index 000000000..005ebf5e4 --- /dev/null +++ b/drivers/net/tokenring/madgemc.c @@ -0,0 +1,806 @@ +/* + * madgemc.c: Driver for the Madge Smart 16/4 MC16 MCA token ring card. + * + * Written 2000 by Adam Fritzler + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * This driver module supports the following cards: + * - Madge Smart 16/4 Ringnode MC16 + * - Madge Smart 16/4 Ringnode MC32 (??) + * + * Maintainer(s): + * AF Adam Fritzler mid@auk.cx + * + * Modification History: + * 16-Jan-00 AF Created + * + */ +static const char *version = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n"; + +#include <linux/module.h> +#include <linux/mca.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> + +#include <linux/netdevice.h> +#include <linux/trdevice.h> +#include "tms380tr.h" +#include "madgemc.h" /* Madge-specific constants */ + +#define MADGEMC_IO_EXTENT 32 +#define MADGEMC_SIF_OFFSET 0x08 + +struct madgemc_card { + struct net_device *dev; + + /* + * These are read from the BIA ROM. + */ + unsigned int manid; + unsigned int cardtype; + unsigned int cardrev; + unsigned int ramsize; + + /* + * These are read from the MCA POS registers. + */ + unsigned int burstmode:2; + unsigned int fairness:1; /* 0 = Fair, 1 = Unfair */ + unsigned int arblevel:4; + unsigned int ringspeed:2; /* 0 = 4mb, 1 = 16, 2 = Auto/none */ + unsigned int cabletype:1; /* 0 = RJ45, 1 = DB9 */ + + struct madgemc_card *next; +}; +static struct madgemc_card *madgemc_card_list = NULL; + + +int madgemc_probe(void); +static int madgemc_open(struct net_device *dev); +static int madgemc_close(struct net_device *dev); +static int madgemc_chipset_init(struct net_device *dev); +static void madgemc_read_rom(struct madgemc_card *card); +static unsigned short madgemc_setnselout_pins(struct net_device *dev); +static void madgemc_setcabletype(struct net_device *dev, int type); + +static int madgemc_mcaproc(char *buf, int slot, void *d); + +static void madgemc_setregpage(struct net_device *dev, int page); +static void madgemc_setsifsel(struct net_device *dev, int val); +static void madgemc_setint(struct net_device *dev, int val); + +static void madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* + * These work around paging, however they dont guarentee you're on the + * right page. + */ +#define SIFREADB(reg) (inb(dev->base_addr + ((reg<0x8)?reg:reg-0x8))) +#define SIFWRITEB(val, reg) (outb(val, dev->base_addr + ((reg<0x8)?reg:reg-0x8))) +#define SIFREADW(reg) (inw(dev->base_addr + ((reg<0x8)?reg:reg-0x8))) +#define SIFWRITEW(val, reg) (outw(val, dev->base_addr + ((reg<0x8)?reg:reg-0x8))) + +/* + * Read a byte-length value from the register. + */ +static unsigned short madgemc_sifreadb(struct net_device *dev, unsigned short reg) +{ + unsigned short ret; + if (reg<0x8) + ret = SIFREADB(reg); + else { + madgemc_setregpage(dev, 1); + ret = SIFREADB(reg); + madgemc_setregpage(dev, 0); + } + return ret; +} + +/* + * Write a byte-length value to a register. + */ +static void madgemc_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) +{ + if (reg<0x8) + SIFWRITEB(val, reg); + else { + madgemc_setregpage(dev, 1); + SIFWRITEB(val, reg); + madgemc_setregpage(dev, 0); + } + return; +} + +/* + * Read a word-length value from a register + */ +static unsigned short madgemc_sifreadw(struct net_device *dev, unsigned short reg) +{ + unsigned short ret; + if (reg<0x8) + ret = SIFREADW(reg); + else { + madgemc_setregpage(dev, 1); + ret = SIFREADW(reg); + madgemc_setregpage(dev, 0); + } + return ret; +} + +/* + * Write a word-length value to a register. + */ +static void madgemc_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) +{ + if (reg<0x8) + SIFWRITEW(val, reg); + else { + madgemc_setregpage(dev, 1); + SIFWRITEW(val, reg); + madgemc_setregpage(dev, 0); + } + return; +} + + + +int __init madgemc_probe(void) +{ + static int versionprinted = 0; + struct net_device *dev; + struct net_local *tp; + struct madgemc_card *card; + int i,slot = 0; + __u8 posreg[4]; + + if (!MCA_bus) + return -1; + + while (slot != MCA_NOTFOUND) { + /* + * Currently we only support the MC16/32 (MCA ID 002d) + */ + slot = mca_find_unused_adapter(0x002d, slot); + if (slot == MCA_NOTFOUND) + break; + + /* + * If we get here, we have an adapter. + */ + if (versionprinted++ == 0) + printk("%s", version); + + if ((dev = init_trdev(NULL, 0))==NULL) { + printk("madgemc: unable to allocate dev space\n"); + return -1; + } + dev->dma = 0; + + /* + * Fetch MCA config registers + */ + for(i=0;i<4;i++) + posreg[i] = mca_read_stored_pos(slot, i+2); + + card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL); + if (card==NULL) { + printk("madgemc: unable to allocate card struct\n"); + return -1; + } + card->dev = dev; + + /* + * Parse configuration information. This all comes + * directly from the publicly available @002d.ADF. + * Get it from Madge or your local ADF library. + */ + + /* + * Base address + */ + dev->base_addr = 0x0a20 + + ((posreg[2] & MC16_POS2_ADDR2)?0x0400:0) + + ((posreg[0] & MC16_POS0_ADDR1)?0x1000:0) + + ((posreg[3] & MC16_POS3_ADDR3)?0x2000:0); + + /* + * Interrupt line + */ + switch(posreg[0] >> 6) { /* upper two bits */ + case 0x1: dev->irq = 3; break; + case 0x2: dev->irq = 9; break; /* IRQ 2 = IRQ 9 */ + case 0x3: dev->irq = 10; break; + default: dev->irq = 0; break; + } + + if (dev->irq == 0) { + printk("%s: invalid IRQ\n", dev->name); + goto getout; + } + + request_region(dev->base_addr, MADGEMC_IO_EXTENT, "madgemc"); +#if 0 + /* why is this not working? */ + if (request_region(dev->base_addr, MADGEMC_IO_EXTENT, + "madgemc")) { + printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", slot, dev->base_addr); + dev->base_addr += MADGEMC_SIF_OFFSET; + goto getout; + } +#endif + dev->base_addr += MADGEMC_SIF_OFFSET; + + /* + * Arbitration Level + */ + card->arblevel = ((posreg[0] >> 1) & 0x7) + 8; + + /* + * Burst mode and Fairness + */ + card->burstmode = ((posreg[2] >> 6) & 0x3); + card->fairness = ((posreg[2] >> 4) & 0x1); + + /* + * Ring Speed + */ + if ((posreg[1] >> 2)&0x1) + card->ringspeed = 2; /* not selected */ + else if ((posreg[2] >> 5) & 0x1) + card->ringspeed = 1; /* 16Mb */ + else + card->ringspeed = 0; /* 4Mb */ + + /* + * Cable type + */ + if ((posreg[1] >> 6)&0x1) + card->cabletype = 1; /* STP/DB9 */ + else + card->cabletype = 0; /* UTP/RJ-45 */ + + + /* + * ROM Info. This requires us to actually twiddle + * bits on the card, so we must ensure above that + * the base address is free of conflict (request_region above). + */ + madgemc_read_rom(card); + + if (card->manid != 0x4d) { /* something went wrong */ + printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid); + goto getout; + } + + if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) { + printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype); + goto getout; + } + + /* All cards except Rev 0 and 1 MC16's have 256kb of RAM */ + if ((card->cardtype == 0x08) && (card->cardrev <= 0x01)) + card->ramsize = 128; + else + card->ramsize = 256; + + printk("%s: %s Rev %d at 0x%04lx IRQ %d\n", + dev->name, + (card->cardtype == 0x08)?MADGEMC16_CARDNAME: + MADGEMC32_CARDNAME, card->cardrev, + dev->base_addr, dev->irq); + + if (card->cardtype == 0x0d) + printk("%s: Warning: MC32 support is experimental and highly untested\n", dev->name); + + if (card->ringspeed==2) { /* Unknown */ + printk("%s: Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name); + card->ringspeed = 1; /* default to 16mb */ + } + + printk("%s: RAM Size: %dKB\n", dev->name, card->ramsize); + + printk("%s: Ring Speed: %dMb/sec on %s\n", dev->name, + (card->ringspeed)?16:4, + card->cabletype?"STP/DB9":"UTP/RJ-45"); + printk("%s: Arbitration Level: %d\n", dev->name, + card->arblevel); + + printk("%s: Burst Mode: ", dev->name); + switch(card->burstmode) { + case 0: printk("Cycle steal"); break; + case 1: printk("Limited burst"); break; + case 2: printk("Delayed release"); break; + case 3: printk("Immediate release"); break; + } + printk(" (%s)\n", (card->fairness)?"Unfair":"Fair"); + + + /* + * Enable SIF before we assign the interrupt handler, + * just in case we get spurious interrupts that need + * handling. + */ + outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */ + madgemc_setsifsel(dev, 1); + if(request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ, + "madgemc", dev)) + goto getout; + + madgemc_chipset_init(dev); /* enables interrupts! */ + madgemc_setcabletype(dev, card->cabletype); + + /* Setup MCA structures */ + mca_set_adapter_name(slot, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); + mca_set_adapter_procfn(slot, madgemc_mcaproc, dev); + mca_mark_as_used(slot); + + printk("%s: Ring Station Address: ", dev->name); + printk("%2.2x", dev->dev_addr[0]); + for (i = 1; i < 6; i++) + printk(":%2.2x", dev->dev_addr[i]); + printk("\n"); + + if (tmsdev_init(dev)) { + printk("%s: unable to get memory for dev->priv.\n", + dev->name); + return -1; + } + tp = (struct net_local *)dev->priv; + + /* + * The MC16 is physically a 32bit card. However, Madge + * insists on calling it 16bit, so I'll assume here that + * they know what they're talking about. Cut off DMA + * at 16mb. + */ + tp->dmalimit = ISA_MAX_ADDRESS; /* XXX: ?? */ + tp->setnselout = madgemc_setnselout_pins; + tp->sifwriteb = madgemc_sifwriteb; + tp->sifreadb = madgemc_sifreadb; + tp->sifwritew = madgemc_sifwritew; + tp->sifreadw = madgemc_sifreadw; + tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4; + + memcpy(tp->ProductID, "Madge MCA 16/4 ", PROD_ID_SIZE + 1); + + dev->open = madgemc_open; + dev->stop = madgemc_close; + + if (register_trdev(dev) == 0) { + /* Enlist in the card list */ + card->next = madgemc_card_list; + madgemc_card_list = card; + } else { + printk("madgemc: register_trdev() returned non-zero.\n"); + + kfree(card); + kfree(dev->priv); + kfree(dev); + return -1; + } + + slot++; + continue; /* successful, try to find another */ + + getout: + release_region(dev->base_addr-MADGEMC_SIF_OFFSET, + MADGEMC_IO_EXTENT); + kfree(card); + kfree(dev); /* release_trdev? */ + slot++; + } + + if (madgemc_card_list) + return 0; + return -1; +} + +/* + * Handle interrupts generated by the card + * + * The MicroChannel Madge cards need slightly more handling + * after an interrupt than other TMS380 cards do. + * + * First we must make sure it was this card that generated the + * interrupt (since interrupt sharing is allowed). Then, + * because we're using level-triggered interrupts (as is + * standard on MCA), we must toggle the interrupt line + * on the card in order to claim and acknowledge the interrupt. + * Once that is done, the interrupt should be handlable in + * the normal tms380tr_interrupt() routine. + * + * There's two ways we can check to see if the interrupt is ours, + * both with their own disadvantages... + * + * 1) Read in the SIFSTS register from the TMS controller. This + * is guarenteed to be accurate, however, there's a fairly + * large performance penalty for doing so: the Madge chips + * must request the register from the Eagle, the Eagle must + * read them from its internal bus, and then take the route + * back out again, for a 16bit read. + * + * 2) Use the MC_CONTROL_REG0_SINTR bit from the Madge ASICs. + * The major disadvantage here is that the accuracy of the + * bit is in question. However, it cuts out the extra read + * cycles it takes to read the Eagle's SIF, as its only an + * 8bit read, and theoretically the Madge bit is directly + * connected to the interrupt latch coming out of the Eagle + * hardware (that statement is not verified). + * + * I can't determine which of these methods has the best win. For now, + * we make a compromise. Use the Madge way for the first interrupt, + * which should be the fast-path, and then once we hit the first + * interrupt, keep on trying using the SIF method until we've + * exhausted all contiguous interrupts. + * + */ +static void madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + int pending,reg1; + struct net_device *dev; + + if (!dev_id) { + printk("madgemc_interrupt: was not passed a dev_id!\n"); + return; + } + + dev = (struct net_device *)dev_id; + + /* Make sure its really us. -- the Madge way */ + pending = inb(dev->base_addr + MC_CONTROL_REG0); + if (!(pending & MC_CONTROL_REG0_SINTR)) + return; /* not our interrupt */ + + /* + * Since we're level-triggered, we may miss the rising edge + * of the next interrupt while we're off handling this one, + * so keep checking until the SIF verifies that it has nothing + * left for us to do. + */ + pending = STS_SYSTEM_IRQ; + do { + if (pending & STS_SYSTEM_IRQ) { + + /* Toggle the interrupt to reset the latch on card */ + reg1 = inb(dev->base_addr + MC_CONTROL_REG1); + outb(reg1 ^ MC_CONTROL_REG1_SINTEN, + dev->base_addr + MC_CONTROL_REG1); + outb(reg1, dev->base_addr + MC_CONTROL_REG1); + + /* Continue handling as normal */ + tms380tr_interrupt(irq, dev_id, regs); + + pending = SIFREADW(SIFSTS); /* restart - the SIF way */ + + } else + return; + } while (1); + + return; /* not reachable */ +} + +/* + * Set the card to the prefered ring speed. + * + * Unlike newer cards, the MC16/32 have their speed selection + * circuit connected to the Madge ASICs and not to the TMS380 + * NSELOUT pins. Set the ASIC bits correctly here, and return + * zero to leave the TMS NSELOUT bits unaffected. + * + */ +unsigned short madgemc_setnselout_pins(struct net_device *dev) +{ + unsigned char reg1; + struct net_local *tp = (struct net_local *)dev->priv; + + reg1 = inb(dev->base_addr + MC_CONTROL_REG1); + + if(tp->DataRate == SPEED_16) + reg1 |= MC_CONTROL_REG1_SPEED_SEL; /* add for 16mb */ + else if (reg1 & MC_CONTROL_REG1_SPEED_SEL) + reg1 ^= MC_CONTROL_REG1_SPEED_SEL; /* remove for 4mb */ + outb(reg1, dev->base_addr + MC_CONTROL_REG1); + + return 0; /* no change */ +} + +/* + * Set the register page. This equates to the SRSX line + * on the TMS380Cx6. + * + * Register selection is normally done via three contiguous + * bits. However, some boards (such as the MC16/32) use only + * two bits, plus a seperate bit in the glue chip. This + * sets the SRSX bit (the top bit). See page 4-17 in the + * Yellow Book for which registers are affected. + * + */ +static void madgemc_setregpage(struct net_device *dev, int page) +{ + static int reg1 = 0; + + reg1 = inb(dev->base_addr + MC_CONTROL_REG1); + if ((page == 0) && (reg1 & MC_CONTROL_REG1_SRSX)) { + outb(reg1 ^ MC_CONTROL_REG1_SRSX, + dev->base_addr + MC_CONTROL_REG1); + } + else if (page == 1) { + outb(reg1 | MC_CONTROL_REG1_SRSX, + dev->base_addr + MC_CONTROL_REG1); + } + reg1 = inb(dev->base_addr + MC_CONTROL_REG1); + + return; +} + +/* + * The SIF registers are not mapped into register space by default + * Set this to 1 to map them, 0 to map the BIA ROM. + * + */ +static void madgemc_setsifsel(struct net_device *dev, int val) +{ + unsigned int reg0; + + reg0 = inb(dev->base_addr + MC_CONTROL_REG0); + if ((val == 0) && (reg0 & MC_CONTROL_REG0_SIFSEL)) { + outb(reg0 ^ MC_CONTROL_REG0_SIFSEL, + dev->base_addr + MC_CONTROL_REG0); + } else if (val == 1) { + outb(reg0 | MC_CONTROL_REG0_SIFSEL, + dev->base_addr + MC_CONTROL_REG0); + } + reg0 = inb(dev->base_addr + MC_CONTROL_REG0); + + return; +} + +/* + * Enable SIF interrupts + * + * This does not enable interrupts in the SIF, but rather + * enables SIF interrupts to be passed onto the host. + * + */ +static void madgemc_setint(struct net_device *dev, int val) +{ + unsigned int reg1; + + reg1 = inb(dev->base_addr + MC_CONTROL_REG1); + if ((val == 0) && (reg1 & MC_CONTROL_REG1_SINTEN)) { + outb(reg1 ^ MC_CONTROL_REG1_SINTEN, + dev->base_addr + MC_CONTROL_REG1); + } else if (val == 1) { + outb(reg1 | MC_CONTROL_REG1_SINTEN, + dev->base_addr + MC_CONTROL_REG1); + } + + return; +} + +/* + * Cable type is set via control register 7. Bit zero high + * for UTP, low for STP. + */ +static void madgemc_setcabletype(struct net_device *dev, int type) +{ + outb((type==0)?MC_CONTROL_REG7_CABLEUTP:MC_CONTROL_REG7_CABLESTP, + dev->base_addr + MC_CONTROL_REG7); +} + +/* + * Enable the functions of the Madge chipset needed for + * full working order. + */ +static int madgemc_chipset_init(struct net_device *dev) +{ + outb(0, dev->base_addr + MC_CONTROL_REG1); /* pull SRESET low */ + tms380tr_wait(100); /* wait for card to reset */ + + /* bring back into normal operating mode */ + outb(MC_CONTROL_REG1_NSRESET, dev->base_addr + MC_CONTROL_REG1); + + /* map SIF registers */ + madgemc_setsifsel(dev, 1); + + /* enable SIF interrupts */ + madgemc_setint(dev, 1); + + return 0; +} + +/* + * Disable the board, and put back into power-up state. + */ +void madgemc_chipset_close(struct net_device *dev) +{ + /* disable interrupts */ + madgemc_setint(dev, 0); + /* unmap SIF registers */ + madgemc_setsifsel(dev, 0); + + return; +} + +/* + * Read the card type (MC16 or MC32) from the card. + * + * The configuration registers are stored in two seperate + * pages. Pages are flipped by clearing bit 3 of CONTROL_REG0 (PAGE) + * for page zero, or setting bit 3 for page one. + * + * Page zero contains the following data: + * Byte 0: Manufacturer ID (0x4D -- ASCII "M") + * Byte 1: Card type: + * 0x08 for MC16 + * 0x0D for MC32 + * Byte 2: Card revision + * Byte 3: Mirror of POS config register 0 + * Byte 4: Mirror of POS 1 + * Byte 5: Mirror of POS 2 + * + * Page one contains the following data: + * Byte 0: Unused + * Byte 1-6: BIA, MSB to LSB. + * + * Note that to read the BIA, we must unmap the SIF registers + * by clearing bit 2 of CONTROL_REG0 (SIFSEL), as the data + * will reside in the same logical location. For this reason, + * _never_ read the BIA while the Eagle processor is running! + * The SIF will be completely inaccessible until the BIA operation + * is complete. + * + */ +static void madgemc_read_rom(struct madgemc_card *card) +{ + unsigned long ioaddr; + unsigned char reg0, reg1, tmpreg0, i; + + ioaddr = card->dev->base_addr; + + reg0 = inb(ioaddr + MC_CONTROL_REG0); + reg1 = inb(ioaddr + MC_CONTROL_REG1); + + /* Switch to page zero and unmap SIF */ + tmpreg0 = reg0 & ~(MC_CONTROL_REG0_PAGE + MC_CONTROL_REG0_SIFSEL); + outb(tmpreg0, ioaddr + MC_CONTROL_REG0); + + card->manid = inb(ioaddr + MC_ROM_MANUFACTURERID); + card->cardtype = inb(ioaddr + MC_ROM_ADAPTERID); + card->cardrev = inb(ioaddr + MC_ROM_REVISION); + + /* Switch to rom page one */ + outb(tmpreg0 | MC_CONTROL_REG0_PAGE, ioaddr + MC_CONTROL_REG0); + + /* Read BIA */ + card->dev->addr_len = 6; + for (i = 0; i < 6; i++) + card->dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i); + + /* Restore original register values */ + outb(reg0, ioaddr + MC_CONTROL_REG0); + outb(reg1, ioaddr + MC_CONTROL_REG1); + + return; +} + +static int madgemc_open(struct net_device *dev) +{ + /* + * Go ahead and reinitialize the chipset again, just to + * make sure we didn't get left in a bad state. + */ + madgemc_chipset_init(dev); + tms380tr_open(dev); + MOD_INC_USE_COUNT; + return 0; +} + +static int madgemc_close(struct net_device *dev) +{ + tms380tr_close(dev); + madgemc_chipset_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * Give some details available from /proc/mca/slotX + */ +static int madgemc_mcaproc(char *buf, int slot, void *d) +{ + struct net_device *dev = (struct net_device *)d; + struct madgemc_card *curcard = madgemc_card_list; + int len = 0; + + while (curcard) { /* search for card struct */ + if (curcard->dev == dev) + break; + curcard = curcard->next; + } + len += sprintf(buf+len, "-------\n"); + if (curcard) { + struct net_local *tp = (struct net_local *)dev->priv; + int i; + + len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev); + len += sprintf(buf+len, "RAM Size: %dkb\n", curcard->ramsize); + len += sprintf(buf+len, "Cable type: %s\n", (curcard->cabletype)?"STP/DB9":"UTP/RJ-45"); + len += sprintf(buf+len, "Configured ring speed: %dMb/sec\n", (curcard->ringspeed)?16:4); + len += sprintf(buf+len, "Running ring speed: %dMb/sec\n", (tp->DataRate==SPEED_16)?16:4); + len += sprintf(buf+len, "Device: %s\n", dev->name); + len += sprintf(buf+len, "IO Port: 0x%04lx\n", dev->base_addr); + len += sprintf(buf+len, "IRQ: %d\n", dev->irq); + len += sprintf(buf+len, "Arbitration Level: %d\n", curcard->arblevel); + len += sprintf(buf+len, "Burst Mode: "); + switch(curcard->burstmode) { + case 0: len += sprintf(buf+len, "Cycle steal"); break; + case 1: len += sprintf(buf+len, "Limited burst"); break; + case 2: len += sprintf(buf+len, "Delayed release"); break; + case 3: len += sprintf(buf+len, "Immediate release"); break; + } + len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair"); + + len += sprintf(buf+len, "Ring Station Address: "); + len += sprintf(buf+len, "%2.2x", dev->dev_addr[0]); + for (i = 1; i < 6; i++) + len += sprintf(buf+len, " %2.2x", dev->dev_addr[i]); + len += sprintf(buf+len, "\n"); + } else + len += sprintf(buf+len, "Card not configured\n"); + + return len; +} + +#ifdef MODULE + +int init_module(void) +{ + /* Probe for cards. */ + if (madgemc_probe()) { + printk(KERN_NOTICE "madgemc.c: No cards found.\n"); + } + /* lock_tms380_module(); */ + return (0); +} + +void cleanup_module(void) +{ + struct net_device *dev; + struct madgemc_card *this_card; + + while (madgemc_card_list) { + dev = madgemc_card_list->dev; + unregister_trdev(dev); + release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT); + free_irq(dev->irq, dev); + kfree(dev->priv); + kfree(dev); + this_card = madgemc_card_list; + madgemc_card_list = this_card->next; + kfree(this_card); + } + /* unlock_tms380_module(); */ +} +#endif /* MODULE */ + + +/* + * Local variables: + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c madgemc.c" + * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c madgemc.c" + * c-set-style "K&R" + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/tokenring/madgemc.h b/drivers/net/tokenring/madgemc.h new file mode 100644 index 000000000..2dd822203 --- /dev/null +++ b/drivers/net/tokenring/madgemc.h @@ -0,0 +1,70 @@ +/* + * madgemc.h: Header for the madgemc tms380tr module + * + * Authors: + * - Adam Fritzler <mid@auk.cx> + */ + +#ifndef __LINUX_MADGEMC_H +#define __LINUX_MADGEMC_H + +#ifdef __KERNEL__ + +#define MADGEMC16_CARDNAME "Madge Smart 16/4 MC16 Ringnode" +#define MADGEMC32_CARDNAME "Madge Smart 16/4 MC32 Ringnode" + +/* + * Bit definitions for the POS config registers + */ +#define MC16_POS0_ADDR1 0x20 +#define MC16_POS2_ADDR2 0x04 +#define MC16_POS3_ADDR3 0x20 + +#define MC_CONTROL_REG0 ((long)-8) /* 0x00 */ +#define MC_CONTROL_REG1 ((long)-7) /* 0x01 */ +#define MC_ADAPTER_POS_REG0 ((long)-6) /* 0x02 */ +#define MC_ADAPTER_POS_REG1 ((long)-5) /* 0x03 */ +#define MC_ADAPTER_POS_REG2 ((long)-4) /* 0x04 */ +#define MC_ADAPTER_REG5_UNUSED ((long)-3) /* 0x05 */ +#define MC_ADAPTER_REG6_UNUSED ((long)-2) /* 0x06 */ +#define MC_CONTROL_REG7 ((long)-1) /* 0x07 */ + +#define MC_CONTROL_REG0_UNKNOWN1 0x01 +#define MC_CONTROL_REG0_UNKNOWN2 0x02 +#define MC_CONTROL_REG0_SIFSEL 0x04 +#define MC_CONTROL_REG0_PAGE 0x08 +#define MC_CONTROL_REG0_TESTINTERRUPT 0x10 +#define MC_CONTROL_REG0_UNKNOWN20 0x20 +#define MC_CONTROL_REG0_SINTR 0x40 +#define MC_CONTROL_REG0_UNKNOWN80 0x80 + +#define MC_CONTROL_REG1_SINTEN 0x01 +#define MC_CONTROL_REG1_BITOFDEATH 0x02 +#define MC_CONTROL_REG1_NSRESET 0x04 +#define MC_CONTROL_REG1_UNKNOWN8 0x08 +#define MC_CONTROL_REG1_UNKNOWN10 0x10 +#define MC_CONTROL_REG1_UNKNOWN20 0x20 +#define MC_CONTROL_REG1_SRSX 0x40 +#define MC_CONTROL_REG1_SPEED_SEL 0x80 + +#define MC_CONTROL_REG7_CABLESTP 0x00 +#define MC_CONTROL_REG7_CABLEUTP 0x01 + +/* + * ROM Page Zero + */ +#define MC_ROM_MANUFACTURERID 0x00 +#define MC_ROM_ADAPTERID 0x01 +#define MC_ROM_REVISION 0x02 +#define MC_ROM_CONFIG0 0x03 +#define MC_ROM_CONFIG1 0x04 +#define MC_ROM_CONFIG2 0x05 + +/* + * ROM Page One + */ +#define MC_ROM_UNUSED_BYTE 0x00 +#define MC_ROM_BIA_START 0x01 + +#endif /* __KERNEL__ */ +#endif /* __LINUX_MADGEMC_H */ diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index ecc43401f..cd353e3f4 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -17,11 +17,10 @@ * JS Jay Schulist <jschlst@turbolinux.com> * * To do: - * 1. MCA SMC TokenCard Support. (Some support is already done). - * 4. Multicast support. + * 1. Multicast support. */ -static const char *version = "smctr.c: v1.0 1/1/00 by jschlst@turbolinux.com\n"; +static const char *version = "smctr.c: v1.1 1/1/00 by jschlst@turbolinux.com\n"; static const char *cardname = "smctr"; #ifdef MODULE @@ -29,6 +28,7 @@ static const char *cardname = "smctr"; #include <linux/version.h> #endif +#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/types.h> @@ -48,6 +48,7 @@ static const char *cardname = "smctr"; #include <linux/errno.h> #include <linux/init.h> #include <linux/pci.h> +#include <linux/mca.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -66,6 +67,10 @@ static unsigned int smctr_portlist[] __initdata = { 0 }; +#ifdef CONFIG_MCA +static unsigned int smctr_posid = 0x6ec6; +#endif + static int ringspeed = 0; /* SMC Name of the Adapter. */ @@ -91,6 +96,7 @@ static int smctr_bypass_state(struct net_device *dev); /* C */ static int smctr_checksum_firmware(struct net_device *dev); +static int __init smctr_chk_isa(struct net_device *dev); static int smctr_chg_rx_mask(struct net_device *dev); static int smctr_clear_int(struct net_device *dev); static int smctr_clear_trc_reset(int ioaddr); @@ -109,11 +115,8 @@ static int smctr_enable_adapter_ctrl_store(struct net_device *dev); static int smctr_enable_adapter_ram(struct net_device *dev); static int smctr_enable_bic_int(struct net_device *dev); -/* F */ -static int __init smctr_find_adapter(struct net_device *dev); - /* G */ -static int __init smctr_get_boardid(struct net_device *dev); +static int __init smctr_get_boardid(struct net_device *dev, int mca); static int smctr_get_group_address(struct net_device *dev); static int smctr_get_functional_address(struct net_device *dev); static unsigned int smctr_get_num_rx_bdbs(struct net_device *dev); @@ -478,13 +481,171 @@ static int smctr_checksum_firmware(struct net_device *dev) return (0); } +static int smctr_chk_mca(struct net_device *dev) +{ +#ifdef CONFIG_MCA + struct net_local *tp = (struct net_local *)dev->priv; + int current_slot; + __u8 r1, r2, r3, r4, r5; + + current_slot = mca_find_unused_adapter(smctr_posid, 0); + if(current_slot == MCA_NOTFOUND) + return (-ENODEV); + + mca_set_adapter_name(current_slot, smctr_name); + mca_mark_as_used(current_slot); + tp->slot_num = current_slot; + + r1 = mca_read_stored_pos(tp->slot_num, 2); + r2 = mca_read_stored_pos(tp->slot_num, 3); + + if(tp->slot_num) + outb(CNFG_POS_CONTROL_REG, (__u8)((tp->slot_num - 1) | CNFG_SLOT_ENABLE_BIT)); + else + outb(CNFG_POS_CONTROL_REG, (__u8)((tp->slot_num) | CNFG_SLOT_ENABLE_BIT)); + + r1 = inb(CNFG_POS_REG1); + r2 = inb(CNFG_POS_REG0); + + tp->bic_type = BIC_594_CHIP; + + /* IO */ + r2 = mca_read_stored_pos(tp->slot_num, 2); + r2 &= 0xF0; + dev->base_addr = ((__u16)r2 << 8) + (__u16)0x800; + request_region(dev->base_addr, SMCTR_IO_EXTENT, smctr_name); + + /* IRQ */ + r5 = mca_read_stored_pos(tp->slot_num, 5); + r5 &= 0xC; + switch(r5) + { + case 0: + dev->irq = 3; + break; + + case 0x4: + dev->irq = 4; + break; + + case 0x8: + dev->irq = 10; + break; + + default: + dev->irq = 15; + break; + } + if(request_irq(dev->irq, smctr_interrupt, SA_SHIRQ, smctr_name, dev)) + return (-ENODEV); + + /* Get RAM base */ + r3 = mca_read_stored_pos(tp->slot_num, 3); + if(r3 & 0x8) + { + if(r3 & 0x80) + tp->ram_base = ((__u32)(r3 & 0x7) << 13) + 0xFD0000; + else + tp->ram_base = ((__u32)(r3 & 0x7) << 13) + 0x0D0000; + } + else + { + if(r3 & 0x80) + tp->ram_base = ((__u32)(r3 & 0x7) << 13) + 0xFC0000; + else + tp->ram_base = ((__u32)(r3 & 0x7) << 13) + 0x0C0000; + } + + /* Get Ram Size */ + r3 &= 0x30; + r3 >>= 4; + + tp->ram_usable = (__u16)CNFG_SIZE_8KB << r3; + tp->ram_size = (__u16)CNFG_SIZE_64KB; + tp->board_id |= TOKEN_MEDIA; + + r4 = mca_read_stored_pos(tp->slot_num, 4); + if(r4 & 0x8) + tp->rom_base = ((__u32)(r4 & 0x7) << 13) + 0xD0000; + else + tp->rom_base = ((__u32)(r4 & 0x7) << 13) + 0xC0000; + + /* Get ROM size. */ + r4 >>= 4; + if(r4 == 0) + tp->rom_size = CNFG_SIZE_8KB; + else + { + if(r4 == 1) + tp->rom_size = CNFG_SIZE_16KB; + else + { + if(r4 == 2) + tp->rom_size = CNFG_SIZE_32KB; + else + tp->rom_size = ROM_DISABLE; + } + } + + /* Get Media Type. */ + r5 = mca_read_stored_pos(tp->slot_num, 5); + r5 &= CNFG_MEDIA_TYPE_MASK; + switch(r5) + { + case (0): + tp->media_type = MEDIA_STP_4; + break; + + case (1): + tp->media_type = MEDIA_STP_16; + break; + + case (3): + tp->media_type = MEDIA_UTP_16; + break; + + default: + tp->media_type = MEDIA_UTP_4; + break; + } + tp->media_menu = 14; + + r2 = mca_read_stored_pos(tp->slot_num, 2); + if(!(r2 & 0x02)) + tp->mode_bits |= EARLY_TOKEN_REL; + + /* Disable slot */ + outb(CNFG_POS_CONTROL_REG, 0); + + tp->board_id = smctr_get_boardid(dev, 1); + switch(tp->board_id & 0xffff) + { + case WD8115TA: + smctr_model = "8115T/A"; + break; + + case WD8115T: + smctr_model = "8115T"; + break; + + default: + smctr_model = "Unknown"; + break; + } + + return (0); +#else + return (-1); +#endif /* CONFIG_MCA */ +} + static int smctr_chg_rx_mask(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; int err = 0; if(smctr_debug > 10) - printk("%s: smctr_chg_rx_mask\n", dev->name); + printk("%s: smctr_chg_rx_mask\n", dev->name); smctr_enable_16bit(dev); smctr_set_page(dev, (__u8 *)tp->ram_access); @@ -804,7 +965,7 @@ static int smctr_enable_bic_int(struct net_device *dev) return (0); } -static int __init smctr_find_adapter(struct net_device *dev) +static int __init smctr_chk_isa(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; @@ -813,7 +974,10 @@ static int __init smctr_find_adapter(struct net_device *dev) int i; if(smctr_debug > 10) - printk("%s: smctr_find_adapter %#4x\n", dev->name, ioaddr); + printk("%s: smctr_chk_isa %#4x\n", dev->name, ioaddr); + + if((ioaddr & 0x1F) != 0) + return (-ENODEV); /* Checksum SMC node address */ for(i = 0; i < 8; i++) @@ -823,7 +987,7 @@ static int __init smctr_find_adapter(struct net_device *dev) } if(chksum != NODE_ADDR_CKSUM) - return (-1); /* Adapter Not Found */ + return (-ENODEV); /* Adapter Not Found */ /* Grab the region so that no one else tries to probe our ioports. */ request_region(ioaddr, SMCTR_IO_EXTENT, smctr_name); @@ -843,7 +1007,7 @@ static int __init smctr_find_adapter(struct net_device *dev) return (-1); /* Get adapter ID */ - tp->board_id = smctr_get_boardid(dev); + tp->board_id = smctr_get_boardid(dev, 0); switch(tp->board_id & 0xffff) { case WD8115TA: @@ -1011,7 +1175,7 @@ static int __init smctr_find_adapter(struct net_device *dev) return (0); } -static int __init smctr_get_boardid(struct net_device *dev) +static int __init smctr_get_boardid(struct net_device *dev, int mca) { struct net_local *tp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; @@ -1020,22 +1184,35 @@ static int __init smctr_get_boardid(struct net_device *dev) tp->board_id = BoardIdMask = 0; - BoardIdMask |= (INTERFACE_CHIP+TOKEN_MEDIA+PAGED_RAM+BOARD_16BIT); - tp->extra_info |= (INTERFACE_584_CHIP + RAM_SIZE_64K - + NIC_825_BIT + ALTERNATE_IRQ_BIT); - - r = inb(ioaddr + BID_REG_1); - r &= 0x0c; - outb(r, ioaddr + BID_REG_1); - r = inb(ioaddr + BID_REG_1); + if(mca) + { + BoardIdMask |= (MICROCHANNEL+INTERFACE_CHIP+TOKEN_MEDIA+PAGED_RAM+BOARD_16BIT); + tp->extra_info |= (INTERFACE_594_CHIP+RAM_SIZE_64K+NIC_825_BIT+ALTERNATE_IRQ_BIT+SLOT_16BIT); + } + else + { + BoardIdMask|=(INTERFACE_CHIP+TOKEN_MEDIA+PAGED_RAM+BOARD_16BIT); + tp->extra_info |= (INTERFACE_584_CHIP + RAM_SIZE_64K + + NIC_825_BIT + ALTERNATE_IRQ_BIT); + } - if(r & BID_SIXTEEN_BIT_BIT) - { - tp->extra_info |= SLOT_16BIT; - tp->adapter_bus = BUS_ISA16_TYPE; - } - else - tp->adapter_bus = BUS_ISA8_TYPE; + if(!mca) + { + r = inb(ioaddr + BID_REG_1); + r &= 0x0c; + outb(r, ioaddr + BID_REG_1); + r = inb(ioaddr + BID_REG_1); + + if(r & BID_SIXTEEN_BIT_BIT) + { + tp->extra_info |= SLOT_16BIT; + tp->adapter_bus = BUS_ISA16_TYPE; + } + else + tp->adapter_bus = BUS_ISA8_TYPE; + } + else + tp->adapter_bus = BUS_MCA_TYPE; /* Get Board Id Byte */ IdByte = inb(ioaddr + BID_BOARD_ID_BYTE); @@ -3536,10 +3713,6 @@ static int __init smctr_probe1(struct net_device *dev, int ioaddr) return (-ENOMEM); #endif - /* See if we have a SMCTR card floating around. */ - if((ioaddr & 0x1F) != 0) - return (-ENODEV); /* No Adapter */ - /* Setup this devices private information structure */ tp = (struct net_local *)kmalloc(sizeof(struct net_local), GFP_KERNEL); @@ -3549,11 +3722,16 @@ static int __init smctr_probe1(struct net_device *dev, int ioaddr) dev->priv = tp; dev->base_addr = ioaddr; - err = smctr_find_adapter(dev); + /* Actually detect an adapter now. */ + err = smctr_chk_isa(dev); if(err < 0) { - kfree_s(tp, sizeof(struct net_local)); - return (-ENODEV); + err = smctr_chk_mca(dev); + if(err < 0) + { + kfree_s(tp, sizeof(struct net_local)); + return (-ENODEV); + } } tp = (struct net_local *)dev->priv; @@ -5696,6 +5874,12 @@ void cleanup_module(void) { if(dev_smctr[i]) { +#ifdef CONFIG_MCA + struct net_local *tp + = (struct net_local *)dev_smctr[i]->priv; + if(tp->slot_num) + mca_mark_as_unused(tp->slot_num); +#endif unregister_trdev(dev_smctr[i]); release_region(dev_smctr[i]->base_addr, SMCTR_IO_EXTENT); diff --git a/drivers/net/tokenring/smctr.h b/drivers/net/tokenring/smctr.h index 4a7c8c3bd..9d447dccf 100644 --- a/drivers/net/tokenring/smctr.h +++ b/drivers/net/tokenring/smctr.h @@ -982,6 +982,9 @@ typedef struct net_local { __u8 join_state; + __u8 slot_num; + __u16 pos_id; + __u32 *ptr_una; __u32 *ptr_bcn_type; __u32 *ptr_tx_fifo_underruns; @@ -1420,11 +1423,9 @@ routine */ * adapter_type The adapter_type field describes the adapter/bus * configuration. */ -#define BUS_UNK_TYPE 0x0000 /* */ #define BUS_ISA16_TYPE 0x0001 /* 16 bit adap in 16 bit (E)ISA slot */ #define BUS_ISA8_TYPE 0x0002 /* 8/16b adap in 8 bit XT/(E)ISA slot */ -#define BUS_MCA_TYPE 0x0003 /* Micro Channel adapter */#define BUS_EISA32M_TYPE 0x0004 /* EISA 32 bit bus master adapter */#define BUS_EISA32S_TYPE 0x0005 /* EISA 32 bit bus slave adapter */#define BUS_PCMCIA_TYPE 0x0006 /* PCMCIA adapter */ -#define BUS_PCI_TYPE 0x0007 /* PCI bus */ +#define BUS_MCA_TYPE 0x0003 /* Micro Channel adapter */ /* * Receive Mask definitions diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 5d024c2d4..7e1933895 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -1,5 +1,5 @@ /* - * tms380tr.c: A network driver for Texas Instruments TMS380-based + * tms380tr.c: A network driver library for Texas Instruments TMS380-based * Token Ring Adapters. * * Originally sktr.c: Written 1997 by Christoph Goos @@ -10,14 +10,16 @@ * This software may be used and distributed according to the terms * of the GNU Public License, incorporated herein by reference. * - * This device driver works with the following TMS380 adapters: + * The following modules are currently available for card support: + * - tmspci (Generic PCI card support) + * - abyss (Madge PCI support) + * + * The following cards are currently lacking support, even + * though they were supported in previous versions, because + * their code did not get migrated into a seperate module: * - SysKonnect TR4/16(+) ISA (SK-4190) - * - SysKonnect TR4/16(+) PCI (SK-4590) - * - SysKonnect TR4/16 PCI (SK-4591) - * - Compaq TR 4/16 PCI - * - Thomas-Conrad TC4048 4/16 PCI - * - 3Com 3C339 Token Link Velocity - * - Any ISA or PCI adapter using only the TMS380 chipset + * They are no longer supported by this driver, at least until + * a module gets written for them. * * Sources: * - The hardware related parts of this driver are take from @@ -27,14 +29,16 @@ * - Also various other drivers in the linux source tree were taken * as samples for some tasks. * - TI TMS380 Second-Generation Token Ring User's Guide - * - TI datasheets for respective chips - * - David Hein at Texas Instruments + * - TI datasheets for respective chips + * - David Hein at Texas Instruments + * - Various Madge employees * * Maintainer(s): * JS Jay Schulist jschlst@turbolinux.com * CG Christoph Goos cgoos@syskonnect.de * AF Adam Fritzler mid@auk.cx - * + * MLP Mike Phillips phillim@amtrak.com + * * Modification History: * 29-Aug-97 CG Created * 04-Apr-98 CG Fixed problems caused by tok_timer_check @@ -42,22 +46,33 @@ * 27-May-98 JS Formated to Linux Kernel Format * 31-May-98 JS Hacked in PCI support * 16-Jun-98 JS Modulized for multiple cards with one driver - * Sep-99 AF Renamed to tms380tr (supports more than SK's) + * Sep-99 AF Renamed to tms380tr (supports more than SK's) * 23-Sep-99 AF Added Compaq and Thomas-Conrad PCI support * Fixed a bug causing double copies on PCI * Fixed for new multicast stuff (2.2/2.3) * 25-Sep-99 AF Uped TPL_NUM from 3 to 9 * Removed extraneous 'No free TPL' + * 22-Dec-99 AF Added Madge PCI Mk2 support and generalized + * parts of the initilization procedure. + * 30-Dec-99 AF Turned tms380tr into a library ala 8390. + * Madge support is provided in the abyss module + * Generic PCI support is in the tmspci module. * * To do: - * 1. Selectable 16 Mbps or 4Mbps - * 2. Multi/Broadcast packet handling (this may have fixed itself) - * + * 1. Multi/Broadcast packet handling (this may have fixed itself) + * 2. Write a sktrisa module that includes the old ISA support + * 3. Allow modules to load their own microcode + * 4. Speed up the BUD process -- freezing the kernel for 3+sec is + * quite unacceptable. + * 5. Still a few remaining stalls when the cable is unplugged. */ -static const char *version = "tms380tr.c: v1.03 29/09/1999 by Christoph Goos, Adam Fritzler\n"; +#ifdef MODULE +static const char *version = "tms380tr.c: v1.07 21/01/2000 by Christoph Goos, Adam Fritzler\n"; +#endif #ifdef MODULE +#define EXPORT_SYMTAB #include <linux/module.h> #include <linux/version.h> #endif @@ -78,6 +93,7 @@ static const char *version = "tms380tr.c: v1.03 29/09/1999 by Christoph Goos, Ad #include <asm/io.h> #include <asm/dma.h> #include <asm/irq.h> +#include <asm/uaccess.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/pci.h> @@ -90,45 +106,6 @@ static const char *version = "tms380tr.c: v1.03 29/09/1999 by Christoph Goos, Ad #include "tms380tr.h" /* Our Stuff */ #include "tms380tr_microcode.h" /* TI microcode for COMMprocessor */ -/* A zero-terminated list of I/O addresses to be probed. */ -static unsigned int tms380tr_portlist[] __initdata = { - 0x0A20, 0x1A20, 0x0B20, 0x1B20, 0x0980, 0x1980, 0x0900, 0x1900, - 0 -}; - -/* A zero-terminated list of IRQs to be probed. - * Used again after initial probe for tms380tr_chipset_init, called from tms380tr_open. - */ -static unsigned short tms380tr_irqlist[] = { - 3, 5, 9, 10, 11, 12, 15, - 0 -}; - -/* A zero-terminated list of DMAs to be probed. */ -static int tms380tr_dmalist[] __initdata = { - 5, 6, 7, - 0 -}; - -/* - * Table used for card detection and type determination. - */ -struct cardinfo_table cardinfo[] = { - { 0, 0, 0, - "Unknown TMS380 Token Ring Adapter"}, - { TMS_ISA, 0, 0, - "SK NET TR 4/16 ISA"}, - { TMS_PCI, PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, - "Compaq 4/16 TR PCI"}, - { TMS_PCI, PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, - "SK NET TR 4/16 PCI"}, - { TMS_PCI, PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, - "Thomas-Conrad TC4048 PCI 4/16"}, - { TMS_PCI, PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C339, - "3Com Token Link Velocity"}, - { 0, 0, 0, NULL} -}; - /* Use 0 for production, 1 for verification, 2 for debug, and * 3 for very verbose debug. */ @@ -137,24 +114,24 @@ struct cardinfo_table cardinfo[] = { #endif static unsigned int tms380tr_debug = TMS380TR_DEBUG; -/* The number of low I/O ports used by the tokencard. */ -#define TMS380TR_IO_EXTENT 32 - /* Index to functions, as function prototypes. * Alphabetical by function name. */ +/* "A" */ /* "B" */ static int tms380tr_bringup_diags(struct net_device *dev); /* "C" */ static void tms380tr_cancel_tx_queue(struct net_local* tp); static int tms380tr_chipset_init(struct net_device *dev); static void tms380tr_chk_irq(struct net_device *dev); +#if 0 static unsigned char tms380tr_chk_frame(struct net_device *dev, unsigned char *Addr); +#endif static void tms380tr_chk_outstanding_cmds(struct net_device *dev); static void tms380tr_chk_src_addr(unsigned char *frame, unsigned char *hw_addr); static unsigned char tms380tr_chk_ssb(struct net_local *tp, unsigned short IrqType); -static int tms380tr_close(struct net_device *dev); +int tms380tr_close(struct net_device *dev); static void tms380tr_cmd_status_irq(struct net_device *dev); /* "D" */ static void tms380tr_disable_interrupts(struct net_device *dev); @@ -176,20 +153,15 @@ static int tms380tr_init_adapter(struct net_device *dev); static int tms380tr_init_card(struct net_device *dev); static void tms380tr_init_ipb(struct net_local *tp); static void tms380tr_init_net_local(struct net_device *dev); -static void tms380tr_init_opb(struct net_local *tp); -static void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int tms380tr_isa_chk_card(struct net_device *dev, int ioaddr, struct cardinfo_table **outcard); -static int tms380tr_isa_chk_ioaddr(int ioaddr); +static void tms380tr_init_opb(struct net_device *dev); +void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs); +/* "M" */ /* "O" */ -static int tms380tr_open(struct net_device *dev); +int tms380tr_open(struct net_device *dev); static void tms380tr_open_adapter(struct net_device *dev); /* "P" */ -static int tms380tr_pci_chk_card(struct net_device *dev, struct cardinfo_table **outcard); -int tms380tr_probe(struct net_device *dev); -static int tms380tr_probe1(struct net_device *dev, int ioaddr); /* "R" */ static void tms380tr_rcv_status_irq(struct net_device *dev); -static void tms380tr_read_addr(struct net_device *dev, unsigned char *Address); static int tms380tr_read_ptr(struct net_device *dev); static void tms380tr_read_ram(struct net_device *dev, unsigned char *Data, unsigned short Address, int Length); @@ -199,6 +171,7 @@ static void tms380tr_ring_status_irq(struct net_device *dev); /* "S" */ static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev); static void tms380tr_set_multicast_list(struct net_device *dev); +static int tms380tr_set_mac_address(struct net_device *dev, void *addr); /* "T" */ static void tms380tr_timer_chk(unsigned long data); static void tms380tr_timer_end_wait(unsigned long data); @@ -207,269 +180,61 @@ static void tms380tr_tx_status_irq(struct net_device *dev); static void tms380tr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[], unsigned int Length); /* "W" */ -static void tms380tr_wait(unsigned long time); +void tms380tr_wait(unsigned long time); static void tms380tr_write_rpl_status(RPL *rpl, unsigned int Status); static void tms380tr_write_tpl_status(TPL *tpl, unsigned int Status); -/* - * Check for a network adapter of this type, and return '0' if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - */ -int __init tms380tr_probe(struct net_device *dev) -{ - int i; - int base_addr = dev ? dev->base_addr : 0; +#define SIFREADB(reg) (((struct net_local *)dev->priv)->sifreadb(dev, reg)) +#define SIFWRITEB(val, reg) (((struct net_local *)dev->priv)->sifwriteb(dev, val, reg)) +#define SIFREADW(reg) (((struct net_local *)dev->priv)->sifreadw(dev, reg)) +#define SIFWRITEW(val, reg) (((struct net_local *)dev->priv)->sifwritew(dev, val, reg)) - if(base_addr > 0x1ff) /* Check a single specified location. */ - return (tms380tr_probe1(dev, base_addr)); - else if(base_addr != 0) /* Don't probe at all. */ - return (-ENXIO); - /* - * Let's check for pci adapters first - */ - if (tms380tr_probe1(dev,0) == 0) /* Success */ - return 0 ; - /* - * No pci cards found, let's check for isa - */ - - for(i = 0; tms380tr_portlist[i]; i++) - { - int ioaddr = tms380tr_portlist[i]; - if(check_region(ioaddr, TMS380TR_IO_EXTENT)) /* Region already used */ - continue; - if(!tms380tr_probe1(dev, ioaddr)) - return (0); - } - - return (-ENODEV); -} - -struct cardinfo_table * __init tms380tr_pci_getcardinfo(unsigned short vendor, - unsigned short device) +#if TMS380TR_DEBUG > 0 +static int madgemc_sifprobe(struct net_device *dev) { - int cur; - for (cur = 1; cardinfo[cur].name != NULL; cur++) { - if (cardinfo[cur].type == 2) /* PCI */ - { - if ((cardinfo[cur].vendor_id == vendor) && (cardinfo[cur].device_id == device)) - return &cardinfo[cur]; - } - } + unsigned char old, chk1, chk2; - return NULL; -} - -/* - * Detect and setup the PCI SysKonnect TR cards in slot order. - */ -static int __init tms380tr_pci_chk_card(struct net_device *dev, - struct cardinfo_table **outcard) -{ - struct pci_dev *pci_device = NULL ; - struct cardinfo_table *card; - int i; - - if(!pci_present()) - return (-1); /* No PCI present. */ - - while ( (pci_device=pci_find_class(PCI_CLASS_NETWORK_TOKEN_RING<<8, pci_device))) { - - unsigned int pci_irq_line; - unsigned int pci_ioaddr; - - /* Remove I/O space marker in bit 0. */ - pci_irq_line = pci_device->irq ; - pci_ioaddr = pci_device->resource[0].start ; -/* pci_ioaddr &= ~3; */ - - /* Don't return from here, just continue on the card discovery loop - MLP */ - if (!(card = tms380tr_pci_getcardinfo(pci_device->vendor, pci_device->device))) - continue ; - - if(check_region(pci_ioaddr, TMS380TR_IO_EXTENT)) - continue; - - request_region(pci_ioaddr, TMS380TR_IO_EXTENT, card->name); - if(request_irq(pci_device->irq, tms380tr_interrupt, SA_SHIRQ, - card->name, dev)) { - release_region(pci_ioaddr, TMS380TR_IO_EXTENT) ; - return (-ENODEV); /* continue; ?? */ - } - /* At this point we have found a valid tms380tr PCI TR card. */ - - pci_ioaddr &= ~3 ; - dev->base_addr = pci_ioaddr; - dev->irq = pci_irq_line; - dev->dma = 0; - - dev->addr_len = 6; - tms380tr_read_addr(dev, (unsigned char*)dev->dev_addr); + old = SIFREADB(SIFADR); /* Get the old SIFADR value */ + + chk1 = 0; /* Begin with check value 0 */ + do { + madgemc_setregpage(dev, 0); + /* Write new SIFADR value */ + SIFWRITEB(chk1, SIFADR); + chk2 = SIFREADB(SIFADR); + if (chk2 != chk1) + return -1; - printk("%s: %s found at %#4x, IRQ %d, ring station ", - dev->name, card->name, pci_ioaddr, dev->irq); - printk("%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - printk(":%2.2x", dev->dev_addr[i]); - printk(".\n"); - - if (outcard) - *outcard = card; - - return 0 ; - } - - return (-1); + madgemc_setregpage(dev, 1); + /* Read, invert and write */ + chk2 = SIFREADB(SIFADD); + if (chk2 != chk1) + return -1; + + madgemc_setregpage(dev, 0); + chk2 ^= 0x0FE; + SIFWRITEB(chk2, SIFADR); + + /* Read, invert and compare */ + madgemc_setregpage(dev, 1); + chk2 = SIFREADB(SIFADD); + madgemc_setregpage(dev, 0); + chk2 ^= 0x0FE; + + if(chk1 != chk2) + return (-1); /* No adapter */ + chk1 -= 2; + } while(chk1 != 0); /* Repeat 128 times (all byte values) */ + + madgemc_setregpage(dev, 0); /* sanity */ + /* Restore the SIFADR value */ + SIFWRITEB(old, SIFADR); + + return (0); } - -/* - * Detect and setup the ISA SysKonnect TR cards. - */ -static int __init tms380tr_isa_chk_card(struct net_device *dev, int ioaddr, - struct cardinfo_table **outcard) -{ - int i, err; - unsigned long flags; - struct cardinfo_table *card = NULL; - - err = tms380tr_isa_chk_ioaddr(ioaddr); - if(err < 0) - return (-ENODEV); - - if(virt_to_bus((void*)((unsigned long)dev->priv+sizeof(struct net_local))) - > ISA_MAX_ADDRESS) - { - printk("%s: Memory not accessible for DMA\n", dev->name); - kfree(dev->priv); - return (-EAGAIN); - } - - /* FIXME */ - card = &cardinfo[1]; - - /* Grab the region so that no one else tries to probe our ioports. */ - request_region(ioaddr, TMS380TR_IO_EXTENT, card->name); - dev->base_addr = ioaddr; - - /* Autoselect IRQ and DMA if dev->irq == 0 */ - if(dev->irq == 0) - { - for(i = 0; tms380tr_irqlist[i] != 0; i++) - { - dev->irq = tms380tr_irqlist[i]; - err = request_irq(dev->irq, &tms380tr_interrupt, 0, card->name, dev); - if(!err) - break; - } - - if(tms380tr_irqlist[i] == 0) - { - printk("%s: AutoSelect no IRQ available\n", dev->name); - return (-EAGAIN); - } - } - else - { - err = request_irq(dev->irq, &tms380tr_interrupt, 0, card->name, dev); - if(err) - { - printk("%s: Selected IRQ not available\n", dev->name); - return (-EAGAIN); - } - } - - /* Always allocate the DMA channel after IRQ and clean up on failure */ - if(dev->dma == 0) - { - for(i = 0; tms380tr_dmalist[i] != 0; i++) - { - dev->dma = tms380tr_dmalist[i]; - err = request_dma(dev->dma, card->name); - if(!err) - break; - } - - if(dev->dma == 0) - { - printk("%s: AutoSelect no DMA available\n", dev->name); - free_irq(dev->irq, NULL); - return (-EAGAIN); - } - } - else - { - err = request_dma(dev->dma, card->name); - if(err) - { - printk("%s: Selected DMA not available\n", dev->name); - free_irq(dev->irq, NULL); - return (-EAGAIN); - } - } - - flags=claim_dma_lock(); - disable_dma(dev->dma); - set_dma_mode(dev->dma, DMA_MODE_CASCADE); - enable_dma(dev->dma); - release_dma_lock(flags); - - printk("%s: %s found at %#4x, using IRQ %d and DMA %d.\n", - dev->name, card->name, ioaddr, dev->irq, dev->dma); - - if (outcard) - *outcard = card; - - return (0); -} - -/* - * Passing an ioaddr of 0 tells us to do a pci card search - */ - -static int __init tms380tr_probe1(struct net_device *dev, int ioaddr) -{ - static unsigned version_printed = 0; - struct net_local *tp; - int err; - struct cardinfo_table *card = NULL; - - if(tms380tr_debug && version_printed++ == 0) - printk(KERN_INFO "%s", version); - -#ifndef MODULE - dev = init_trdev(dev, 0); - if(dev == NULL) - return (-ENOMEM); #endif - if (ioaddr == 0) { - err = tms380tr_pci_chk_card(dev, &card); - } else { - err = tms380tr_isa_chk_card(dev, ioaddr, &card); - } - if(err < 0) - return (-ENODEV); - - /* Setup this devices private information structure */ - tp = (struct net_local *)kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA); - if(tp == NULL) - return (-ENOMEM); - memset(tp, 0, sizeof(struct net_local)); - init_waitqueue_head(&tp->wait_for_tok_int); - tp->CardType = card; - - dev->priv = tp; - dev->init = tms380tr_init_card; - dev->open = tms380tr_open; - dev->stop = tms380tr_close; - dev->do_ioctl = NULL ; - dev->hard_start_xmit = tms380tr_send_packet; - dev->get_stats = tms380tr_get_stats; - dev->set_multicast_list = &tms380tr_set_multicast_list; - return (0); -} /* Dummy function */ static int __init tms380tr_init_card(struct net_device *dev) @@ -481,42 +246,6 @@ static int __init tms380tr_init_card(struct net_device *dev) } /* - * This function tests if an adapter is really installed at the - * given I/O address. Return negative if no adapter at IO addr. - */ -static int __init tms380tr_isa_chk_ioaddr(int ioaddr) -{ - unsigned char old, chk1, chk2; - - old = inb(ioaddr + SIFADR); /* Get the old SIFADR value */ - - chk1 = 0; /* Begin with check value 0 */ - do { - /* Write new SIFADR value */ - outb(chk1, ioaddr + SIFADR); - - /* Read, invert and write */ - chk2 = inb(ioaddr + SIFADD); - chk2 ^= 0x0FE; - outb(chk2, ioaddr + SIFADR); - - /* Read, invert and compare */ - chk2 = inb(ioaddr + SIFADD); - chk2 ^= 0x0FE; - - if(chk1 != chk2) - return (-1); /* No adapter */ - - chk1 -= 2; - } while(chk1 != 0); /* Repeat 128 times (all byte values) */ - - /* Restore the SIFADR value */ - outb(old, ioaddr + SIFADR); - - return (0); -} - -/* * Open/initialize the board. This is called sometime after * booting when the 'ifconfig' program is run. * @@ -524,14 +253,14 @@ static int __init tms380tr_isa_chk_ioaddr(int ioaddr) * registers that "should" only need to be set once at boot, so that * there is non-reboot way to recover if something goes wrong. */ -static int tms380tr_open(struct net_device *dev) +int tms380tr_open(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; int err; /* Reset the hardware here. Don't forget to set the station address. */ err = tms380tr_chipset_init(dev); - if(err) + if(err) { printk(KERN_INFO "%s: Chipset initialization error\n", dev->name); @@ -548,7 +277,6 @@ static int tms380tr_open(struct net_device *dev) printk(KERN_INFO "%s: Adapter RAM size: %dK\n", dev->name, tms380tr_read_ptr(dev)); - tms380tr_enable_interrupts(dev); tms380tr_open_adapter(dev); @@ -566,8 +294,8 @@ static int tms380tr_open(struct net_device *dev) /* If AdapterVirtOpenFlag is 1, the adapter is now open for use */ if(tp->AdapterVirtOpenFlag == 0) { - tms380tr_disable_interrupts(dev); - return (-1); + tms380tr_disable_interrupts(dev); + return (-1); } dev->start = 1; @@ -579,10 +307,6 @@ static int tms380tr_open(struct net_device *dev) tp->timer.function = tms380tr_timer_chk; tp->timer.data = (unsigned long)dev; add_timer(&tp->timer); - -#ifdef MODULE - MOD_INC_USE_COUNT; -#endif return (0); } @@ -610,47 +334,20 @@ static void tms380tr_timer_end_wait(unsigned long data) static int tms380tr_chipset_init(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; - unsigned char PosReg, Tmp; - int i, err; + int err; tms380tr_init_ipb(tp); - tms380tr_init_opb(tp); + tms380tr_init_opb(dev); tms380tr_init_net_local(dev); - /* Set pos register: selects irq and dma channel. - * Only for ISA bus adapters. - */ - if(dev->dma > 0) - { - PosReg = 0; - for(i = 0; tms380tr_irqlist[i] != 0; i++) - { - if(tms380tr_irqlist[i] == dev->irq) - break; - } - - /* Choose default cycle time, 500 nsec */ - PosReg |= CYCLE_TIME << 2; - PosReg |= i << 4; - i = dev->dma - 5; - PosReg |= i; - - if(tp->DataRate == SPEED_4) - PosReg |= LINE_SPEED_BIT; - else - PosReg &= ~LINE_SPEED_BIT; - - outb(PosReg, dev->base_addr + POSREG); - Tmp = inb(dev->base_addr + POSREG); - if((Tmp & ~CYCLE_TIME) != (PosReg & ~CYCLE_TIME)) - printk(KERN_INFO "%s: POSREG error\n", dev->name); - } err = tms380tr_reset_adapter(dev); if(err < 0) return (-1); + err = tms380tr_bringup_diags(dev); if(err < 0) return (-1); + err = tms380tr_init_adapter(dev); if(err < 0) return (-1); @@ -690,7 +387,7 @@ static void tms380tr_init_net_local(struct net_device *dev) skb_queue_head_init(&tp->SendSkbQueue); tp->QueueSkb = MAX_TX_QUEUE; - + /* Create circular chain of transmit lists */ for (i = 0; i < TPL_NUM; i++) { @@ -713,7 +410,7 @@ static void tms380tr_init_net_local(struct net_device *dev) tp->Rpl[i].NextRPLAddr = htonl((unsigned long) virt_to_bus(&tp->Rpl[(i+1) % RPL_NUM])); tp->Rpl[i].Status = (RX_VALID | RX_START_FRAME | RX_END_FRAME | RX_FRAME_IRQ); tp->Rpl[i].FrameSize = 0; - tp->Rpl[i].FragList[0].DataCount = SWAPB(tp->MaxPacketSize); + tp->Rpl[i].FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize); /* Alloc skb and point adapter to data area */ tp->Rpl[i].Skb = dev_alloc_skb(tp->MaxPacketSize); @@ -731,7 +428,7 @@ static void tms380tr_init_net_local(struct net_device *dev) skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize); /* data unreachable for DMA ? then use local buffer */ - if(tp->CardType->type == TMS_ISA && virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > ISA_MAX_ADDRESS) + if(tp->dmalimit && virt_to_bus(tp->Rpl[i].Skb->data) + tp->MaxPacketSize > tp->dmalimit) { tp->Rpl[i].SkbStat = SKB_DATA_COPY; tp->Rpl[i].FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[i])); @@ -780,28 +477,37 @@ static void tms380tr_init_ipb(struct net_local *tp) /* * Initializes the open parameter block. */ -static void tms380tr_init_opb(struct net_local *tp) +static void tms380tr_init_opb(struct net_device *dev) { + struct net_local *tp; unsigned long Addr; unsigned short RplSize = RPL_SIZE; unsigned short TplSize = TPL_SIZE; unsigned short BufferSize = BUFFER_SIZE; + int i; + + tp = (struct net_local *)dev->priv; tp->ocpl.OPENOptions = 0; tp->ocpl.OPENOptions |= ENABLE_FULL_DUPLEX_SELECTION; tp->ocpl.FullDuplex = 0; tp->ocpl.FullDuplex |= OPEN_FULL_DUPLEX_OFF; - /* Fixme: If mac address setable: - * for (i=0; i<LENGTH_OF_ADDRESS; i++) - * mac->Vam->ocpl.NodeAddr[i] = mac->CurrentAddress[i]; + /* + * Set node address + * + * We go ahead and put it in the OPB even though on + * most of the generic adapters this isn't required. + * Its simpler this way. -- ASF */ + for (i=0;i<6;i++) + tp->ocpl.NodeAddr[i] = ((unsigned char *)dev->dev_addr)[i]; tp->ocpl.GroupAddr = 0; tp->ocpl.FunctAddr = 0; - tp->ocpl.RxListSize = SWAPB(RplSize); - tp->ocpl.TxListSize = SWAPB(TplSize); - tp->ocpl.BufSize = SWAPB(BufferSize); + tp->ocpl.RxListSize = cpu_to_be16((unsigned short)RplSize); + tp->ocpl.TxListSize = cpu_to_be16((unsigned short)TplSize); + tp->ocpl.BufSize = cpu_to_be16((unsigned short)BufferSize); tp->ocpl.Reserved = 0; tp->ocpl.TXBufMin = TX_BUF_MIN; tp->ocpl.TXBufMax = TX_BUF_MAX; @@ -836,7 +542,7 @@ static void tms380tr_open_adapter(struct net_device *dev) */ static void tms380tr_disable_interrupts(struct net_device *dev) { - outb(0, dev->base_addr + SIFACL); + SIFWRITEB(0, SIFACL); return; } @@ -847,7 +553,7 @@ static void tms380tr_disable_interrupts(struct net_device *dev) */ static void tms380tr_enable_interrupts(struct net_device *dev) { - outb(ACL_SINTEN, dev->base_addr + SIFACL); + SIFWRITEB(ACL_SINTEN, SIFACL); return; } @@ -948,8 +654,7 @@ static void tms380tr_hardware_send_packet(struct net_device *dev, struct net_loc tp->QueueSkb++; /* Is buffer reachable for Busmaster-DMA? */ - if(tp->CardType->type == TMS_ISA && virt_to_bus((void*)(((long) skb->data) + skb->len)) - > ISA_MAX_ADDRESS) + if(tp->dmalimit && virt_to_bus((void*)(((long) skb->data) + skb->len)) > tp->dmalimit) { /* Copy frame to local buffer */ i = tp->TplFree->TPLIndex; @@ -975,11 +680,11 @@ static void tms380tr_hardware_send_packet(struct net_device *dev, struct net_loc /* Save the skb for delayed return of skb to system */ tpl->Skb = skb; - tpl->FragList[0].DataCount = (unsigned short) SWAPB(length); + tpl->FragList[0].DataCount = cpu_to_be16((unsigned short)length); tpl->FragList[0].DataAddr = htonl(virt_to_bus(newbuf)); /* Write the data length in the transmit list. */ - tpl->FrameSize = (unsigned short) SWAPB(length); + tpl->FrameSize = cpu_to_be16((unsigned short)length); tpl->MData = newbuf; /* Transmit the frame and set the status values. */ @@ -1057,48 +762,41 @@ static void tms380tr_timer_chk(unsigned long data) /* * The typical workload of the driver: Handle the network interface interrupts. */ -static void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs) +void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; struct net_local *tp; - int ioaddr; unsigned short irq_type; - if(dev == NULL) - { + if(dev == NULL) { printk("%s: irq %d for unknown device.\n", dev->name, irq); return; } dev->interrupt = 1; - ioaddr = dev->base_addr; tp = (struct net_local *)dev->priv; - irq_type = inw(ioaddr + SIFSTS); + irq_type = SIFREADW(SIFSTS); - while(irq_type & STS_SYSTEM_IRQ) - { + while(irq_type & STS_SYSTEM_IRQ) { irq_type &= STS_IRQ_MASK; - if(!tms380tr_chk_ssb(tp, irq_type)) - { + if(!tms380tr_chk_ssb(tp, irq_type)) { printk(KERN_INFO "%s: DATA LATE occurred\n", dev->name); break; } - switch(irq_type) - { - case STS_IRQ_RECEIVE_STATUS: - tms380tr_reset_interrupt(dev); - tms380tr_rcv_status_irq(dev); - break; + switch(irq_type) { + case STS_IRQ_RECEIVE_STATUS: + tms380tr_reset_interrupt(dev); + tms380tr_rcv_status_irq(dev); + break; - case STS_IRQ_TRANSMIT_STATUS: - /* Check if TRANSMIT.HALT command is complete */ - if(tp->ssb.Parm[0] & COMMAND_COMPLETE) - { - tp->TransmitCommandActive = 0; + case STS_IRQ_TRANSMIT_STATUS: + /* Check if TRANSMIT.HALT command is complete */ + if(tp->ssb.Parm[0] & COMMAND_COMPLETE) { + tp->TransmitCommandActive = 0; tp->TransmitHaltScheduled = 0; /* Issue a new transmit command. */ @@ -1109,40 +807,51 @@ static void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs) tms380tr_tx_status_irq(dev); break; - case STS_IRQ_COMMAND_STATUS: - /* The SSB contains status of last command - * other than receive/transmit. - */ - tms380tr_cmd_status_irq(dev); - break; - - case STS_IRQ_SCB_CLEAR: - /* The SCB is free for another command. */ - tp->ScbInUse = 0; - tms380tr_chk_outstanding_cmds(dev); - break; - - case STS_IRQ_RING_STATUS: - tms380tr_ring_status_irq(dev); - break; + case STS_IRQ_COMMAND_STATUS: + /* The SSB contains status of last command + * other than receive/transmit. + */ + tms380tr_cmd_status_irq(dev); + break; + + case STS_IRQ_SCB_CLEAR: + /* The SCB is free for another command. */ + tp->ScbInUse = 0; + tms380tr_chk_outstanding_cmds(dev); + break; + + case STS_IRQ_RING_STATUS: + tms380tr_ring_status_irq(dev); + break; - case STS_IRQ_ADAPTER_CHECK: - tms380tr_chk_irq(dev); - break; + case STS_IRQ_ADAPTER_CHECK: + tms380tr_chk_irq(dev); + break; - default: - printk(KERN_INFO "Unknown Token Ring IRQ\n"); - break; + case STS_IRQ_LLC_STATUS: + printk(KERN_DEBUG "tms380tr: unexpected LLC status IRQ\n"); + break; + + case STS_IRQ_TIMER: + printk(KERN_DEBUG "tms380tr: unexpected Timer IRQ\n"); + break; + + case STS_IRQ_RECEIVE_PENDING: + printk(KERN_DEBUG "tms380tr: unexpected Receive Pending IRQ\n"); + break; + + default: + printk(KERN_INFO "Unknown Token Ring IRQ (0x%04x)\n", irq_type); + break; } /* Reset system interrupt if not already done. */ if(irq_type != STS_IRQ_TRANSMIT_STATUS - && irq_type != STS_IRQ_RECEIVE_STATUS) - { + && irq_type != STS_IRQ_RECEIVE_STATUS) { tms380tr_reset_interrupt(dev); } - irq_type = inw(ioaddr + SIFSTS); + irq_type = SIFREADW(SIFSTS); } dev->interrupt = 0; @@ -1436,7 +1145,7 @@ static void tms380tr_cmd_status_irq(struct net_device *dev) /* * The inverse routine to tms380tr_open(). */ -static int tms380tr_close(struct net_device *dev) +int tms380tr_close(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; dev->tbusy = 1; @@ -1469,13 +1178,9 @@ static int tms380tr_close(struct net_device *dev) release_dma_lock(flags); } - outw(0xFF00, dev->base_addr + SIFCMD); - if(dev->dma > 0) - outb(0xff, dev->base_addr + POSREG); - -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif + SIFWRITEW(0xFF00, SIFCMD); + if(dev->dma > 0) /* what the? */ + SIFWRITEB(0xff, POSREG); tms380tr_cancel_tx_queue(tp); @@ -1549,7 +1254,7 @@ static void tms380tr_set_multicast_list(struct net_device *dev) /* * Wait for some time (microseconds) */ -static void tms380tr_wait(unsigned long time) +void tms380tr_wait(unsigned long time) { #if 0 long tmp; @@ -1570,7 +1275,6 @@ static void tms380tr_wait(unsigned long time) */ static void tms380tr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue) { - int ioaddr = dev->base_addr; unsigned short cmd; unsigned short SifStsValue; unsigned long loop_counter; @@ -1579,9 +1283,9 @@ static void tms380tr_exec_sifcmd(struct net_device *dev, unsigned int WriteValue cmd = (unsigned short)WriteValue; loop_counter = 0,5 * 800000; do { - SifStsValue = inw(ioaddr + SIFSTS); + SifStsValue = SIFREADW(SIFSTS); } while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--); - outw(cmd, ioaddr + SIFCMD); + SIFWRITEW(cmd, SIFCMD); return; } @@ -1595,22 +1299,19 @@ static int tms380tr_reset_adapter(struct net_device *dev) struct net_local *tp = (struct net_local *)dev->priv; unsigned short *fw_ptr = (unsigned short *)&tms380tr_code; unsigned short count, c; - int ioaddr = dev->base_addr; /* Hardware adapter reset */ - outw(ACL_ARESET, ioaddr + SIFACL); + SIFWRITEW(ACL_ARESET, SIFACL); tms380tr_wait(40); - c = inw(ioaddr + SIFACL); + c = SIFREADW(SIFACL); tms380tr_wait(20); if(dev->dma == 0) /* For PCI adapters */ { - c &= ~(ACL_SPEED4 | ACL_SPEED16); /* Clear bits */ - if(tp->DataRate == SPEED_4) - c |= ACL_SPEED4; /* Set 4Mbps */ - else - c |= ACL_SPEED16; /* Set 16Mbps */ + c &= ~(ACL_NSELOUT0 | ACL_NSELOUT1); /* Clear bits */ + if(tp->setnselout) + c |= (*tp->setnselout)(dev); } /* In case a command is pending - forget it */ @@ -1618,18 +1319,20 @@ static int tms380tr_reset_adapter(struct net_device *dev) c &= ~ACL_ARESET; /* Clear adapter reset bit */ c |= ACL_CPHALT; /* Halt adapter CPU, allow download */ + c |= ACL_BOOT; + c |= ACL_SINTEN; c &= ~ACL_PSDMAEN; /* Clear pseudo dma bit */ - outw(c, ioaddr + SIFACL); + SIFWRITEW(c, SIFACL); tms380tr_wait(40); /* Download firmware via DIO interface: */ do { /* Download first address part */ - outw(*fw_ptr, ioaddr + SIFADX); + SIFWRITEW(*fw_ptr, SIFADX); fw_ptr++; /* Download second address part */ - outw(*fw_ptr, ioaddr + SIFADD); + SIFWRITEW(*fw_ptr, SIFADD); fw_ptr++; if((count = *fw_ptr) != 0) /* Load loop counter */ @@ -1637,17 +1340,17 @@ static int tms380tr_reset_adapter(struct net_device *dev) fw_ptr++; /* Download block data */ for(; count > 0; count--) { - outw(*fw_ptr, ioaddr + SIFINC); + SIFWRITEW(*fw_ptr, SIFINC); fw_ptr++; } } else /* Stop, if last block downloaded */ { - c = inw(ioaddr + SIFACL); + c = SIFREADW(SIFACL); c &= (~ACL_CPHALT | ACL_SINTEN); /* Clear CPHALT and start BUD */ - outw(c, ioaddr + SIFACL); + SIFWRITEW(c, SIFACL); return (1); } } while(count == 0); @@ -1663,7 +1366,6 @@ static int tms380tr_bringup_diags(struct net_device *dev) { int loop_cnt, retry_cnt; unsigned short Status; - int ioaddr = dev->base_addr; tms380tr_wait(HALF_SECOND); tms380tr_exec_sifcmd(dev, EXEC_SOFT_RESET); @@ -1679,7 +1381,7 @@ static int tms380tr_bringup_diags(struct net_device *dev) do { /* Inspect BUD results */ loop_cnt--; tms380tr_wait(HALF_SECOND); - Status = inw(ioaddr + SIFSTS); + Status = SIFREADW(SIFSTS); Status &= STS_MASK; if(tms380tr_debug > 3) @@ -1701,11 +1403,16 @@ static int tms380tr_bringup_diags(struct net_device *dev) } } while(retry_cnt > 0); - Status = inw(ioaddr + SIFSTS); - Status &= STS_ERROR_MASK; /* Hardware error occurred! */ - - printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", - dev->name, Status); + Status = SIFREADW(SIFSTS); + + /* Hardware error occurred! */ + Status &= 0x001f; + if (Status & 0x0010) + printk(KERN_INFO "%s: BUD Error: Timeout\n", dev->name); + else if ((Status & 0x000f) > 6) + printk(KERN_INFO "%s: BUD Error: Illegal Failure\n", dev->name); + else + printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", dev->name, Status & 0x000f); return (-1); } @@ -1727,7 +1434,6 @@ static int tms380tr_init_adapter(struct net_device *dev) unsigned char *sb_ptr = (unsigned char *) &tp->ssb; unsigned short Status; int i, loop_cnt, retry_cnt; - int ioaddr = dev->base_addr; /* Normalize: byte order low/high, word order high/low! (only IPB!) */ tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb)); @@ -1740,14 +1446,14 @@ static int tms380tr_init_adapter(struct net_device *dev) retry_cnt--; /* Transfer initialization block */ - outw(0x0001, ioaddr + SIFADX); + SIFWRITEW(0x0001, SIFADX); /* To address 0001:0A00 of adapter RAM */ - outw(0x0A00, ioaddr + SIFADD); + SIFWRITEW(0x0A00, SIFADD); /* Write 11 words to adapter RAM */ for(i = 0; i < 11; i++) - outw(ipb_ptr[i], ioaddr + SIFINC); + SIFWRITEW(ipb_ptr[i], SIFINC); /* Execute SCB adapter command */ tms380tr_exec_sifcmd(dev, CMD_EXECUTE); @@ -1761,7 +1467,7 @@ static int tms380tr_init_adapter(struct net_device *dev) tms380tr_wait(HALF_SECOND); /* Mask interesting status bits */ - Status = inw(ioaddr + SIFSTS); + Status = SIFREADW(SIFSTS); Status &= STS_MASK; } while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0) && ((Status & STS_ERROR) == 0) && (loop_cnt != 0)); @@ -1792,7 +1498,7 @@ static int tms380tr_init_adapter(struct net_device *dev) if((Status & STS_ERROR) != 0) { /* Initialization error occurred */ - Status = inw(ioaddr + SIFSTS); + Status = SIFREADW(SIFSTS); Status &= STS_ERROR_MASK; /* ShowInitialisationErrorCode(Status); */ return (-1); /* Unrecoverable error */ @@ -1820,7 +1526,6 @@ static void tms380tr_chk_outstanding_cmds(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; unsigned long Addr = 0; - unsigned char i = 0; if(tp->CMDqueue == 0) return; /* No command execution */ @@ -1839,14 +1544,6 @@ static void tms380tr_chk_outstanding_cmds(struct net_device *dev) /* Execute OPEN command */ tp->CMDqueue ^= OC_OPEN; - /* Copy the 18 bytes of the product ID */ - while((tp->CardType->name[i] != '\0') - && (i < PROD_ID_SIZE)) - { - tp->ProductID[i] = tp->CardType->name[i]; - i++; - } - Addr = htonl(virt_to_bus(&tp->ocpl)); tp->scb.Parm[0] = LOWORD(Addr); tp->scb.Parm[1] = HIWORD(Addr); @@ -2001,7 +1698,7 @@ static void tms380tr_ring_status_irq(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; - tp->CurrentRingStatus = SWAPB(tp->ssb.Parm[0]); + tp->CurrentRingStatus = be16_to_cpu((unsigned short)tp->ssb.Parm[0]); /* First: fill up statistics */ if(tp->ssb.Parm[0] & SIGNAL_LOSS) @@ -2071,19 +1768,18 @@ static void tms380tr_chk_irq(struct net_device *dev) { int i; unsigned short AdapterCheckBlock[4]; - unsigned short ioaddr = dev->base_addr; struct net_local *tp = (struct net_local *)dev->priv; tp->AdapterOpenFlag = 0; /* Adapter closed now */ /* Page number of adapter memory */ - outw(0x0001, ioaddr + SIFADX); + SIFWRITEW(0x0001, SIFADX); /* Address offset */ - outw(CHECKADDR, ioaddr + SIFADR); + SIFWRITEW(CHECKADDR, SIFADR); /* Reading 8 byte adapter check block. */ for(i = 0; i < 4; i++) - AdapterCheckBlock[i] = inw(ioaddr + SIFINC); + AdapterCheckBlock[i] = SIFREADW(SIFINC); if(tms380tr_debug > 3) { @@ -2234,8 +1930,8 @@ static int tms380tr_read_ptr(struct net_device *dev) tms380tr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr, ADAPTER_INT_PTRS, 16); tms380tr_read_ram(dev, (unsigned char *)&adapterram, - (unsigned short)SWAPB(tp->intptrs.AdapterRAMPtr), 2); - return SWAPB(adapterram); + cpu_to_be16((unsigned short)tp->intptrs.AdapterRAMPtr), 2); + return be16_to_cpu(adapterram); } /* @@ -2246,22 +1942,21 @@ static void tms380tr_read_ram(struct net_device *dev, unsigned char *Data, { int i; unsigned short old_sifadx, old_sifadr, InWord; - unsigned short ioaddr = dev->base_addr; /* Save the current values */ - old_sifadx = inw(ioaddr + SIFADX); - old_sifadr = inw(ioaddr + SIFADR); + old_sifadx = SIFREADW(SIFADX); + old_sifadr = SIFREADW(SIFADR); /* Page number of adapter memory */ - outw(0x0001, ioaddr + SIFADX); + SIFWRITEW(0x0001, SIFADX); /* Address offset in adapter RAM */ - outw(Address, ioaddr + SIFADR); + SIFWRITEW(Address, SIFADR); /* Copy len byte from adapter memory to system data area. */ i = 0; for(;;) { - InWord = inw(ioaddr + SIFINC); + InWord = SIFREADW(SIFINC); *(Data + i) = HIBYTE(InWord); /* Write first byte */ if(++i == Length) /* All is done break */ @@ -2273,30 +1968,8 @@ static void tms380tr_read_ram(struct net_device *dev, unsigned char *Data, } /* Restore original values */ - outw(old_sifadx, ioaddr + SIFADX); - outw(old_sifadr, ioaddr + SIFADR); - - return; -} - -/* - * Reads MAC address from adapter ROM. - */ -static void tms380tr_read_addr(struct net_device *dev, unsigned char *Address) -{ - int i, In; - unsigned short ioaddr = dev->base_addr; - - /* Address: 0000:0000 */ - outw(0, ioaddr + SIFADX); - outw(0, ioaddr + SIFADR); - - /* Read six byte MAC address data */ - for(i = 0; i < 6; i++) - { - In = inw(ioaddr + SIFINC); - *(Address + i) = (unsigned char)(In >> 8); - } + SIFWRITEW(old_sifadx, SIFADX); + SIFWRITEW(old_sifadr, SIFADR); return; } @@ -2447,7 +2120,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) /* Get the frame size (Byte swap for Intel). * Do this early (see workaround comment below) */ - Length = (unsigned short)SWAPB(rpl->FrameSize); + Length = be16_to_cpu((unsigned short)rpl->FrameSize); /* Check if the Frame_Start, Frame_End and * Frame_Complete bits are set. @@ -2463,15 +2136,16 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) * Length2 is there because there have also been * cases where the FrameSize was partially written */ - Length2 = (unsigned short)SWAPB(rpl->FrameSize); + Length2 = be16_to_cpu((unsigned short)rpl->FrameSize); if(Length == 0 || Length != Length2) { tp->RplHead = SaveHead; break; /* Return to tms380tr_interrupt */ } -#if 0 /* This might happen for multicast or broadcast packets. - The upper layers are expected to handle this, not here */ +#if 0 /* This might happen for multicast or broadcast packets. + The upper layers are expected to handle this, not here */ + /* Drop frames sent by myself */ if(tms380tr_chk_frame(dev, rpl->MData)) { @@ -2552,8 +2226,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) skb_put(rpl->Skb, tp->MaxPacketSize); /* Data unreachable for DMA ? then use local buffer */ - if(tp->CardType->type == TMS_ISA && virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize - > ISA_MAX_ADDRESS) + if(tp->dmalimit && virt_to_bus(rpl->Skb->data) + tp->MaxPacketSize > tp->dmalimit) { rpl->SkbStat = SKB_DATA_COPY; rpl->FragList[0].DataAddr = htonl(virt_to_bus(tp->LocalRxBuffers[rpl->RPLIndex])); @@ -2568,7 +2241,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) } } - rpl->FragList[0].DataCount = SWAPB(tp->MaxPacketSize); + rpl->FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize); rpl->FrameSize = 0; /* Pass the last RPL back to the adapter */ @@ -2619,6 +2292,7 @@ static void tms380tr_update_rcv_stats(struct net_local *tp, unsigned char DataPt return; } +#if 0 /* * Check if it is a frame of myself. Compare source address with my current * address in reverse direction, and mask out the TR_RII. @@ -2639,6 +2313,20 @@ static unsigned char tms380tr_chk_frame(struct net_device *dev, unsigned char *A return (1); /* It is my frame. */ } +#endif + +static int tms380tr_set_mac_address(struct net_device *dev, void *addr) +{ + struct net_local *tp = (struct net_local *)dev->priv; + struct sockaddr *saddr = addr; + + if (tp->AdapterOpenFlag || tp->AdapterVirtOpenFlag) { + printk(KERN_WARNING "%s: Cannot set MAC/LAA address while card is open\n", dev->name); + return -EIO; + } + memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len); + return 0; +} #if TMS380TR_DEBUG > 0 /* @@ -2651,80 +2339,73 @@ static void tms380tr_dump(unsigned char *Data, int length) for (i = 0, j = 0; i < length / 8; i++, j += 8) { printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n", - Data[j+0],Data[j+1],Data[j+2],Data[j+3], - Data[j+4],Data[j+5],Data[j+6],Data[j+7]); + Data[j+0],Data[j+1],Data[j+2],Data[j+3], + Data[j+4],Data[j+5],Data[j+6],Data[j+7]); } return; } #endif +int tmsdev_init(struct net_device *dev) +{ + if (dev->priv == NULL) + { + struct net_local *tms_local; + + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL | GFP_DMA); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_local)); + tms_local = (struct net_local *)dev->priv; + init_waitqueue_head(&tms_local->wait_for_tok_int); + } + + /* These can be overridden by the card driver if needed */ + dev->init = tms380tr_init_card; + dev->open = tms380tr_open; + dev->stop = tms380tr_close; + dev->do_ioctl = NULL; + dev->hard_start_xmit = tms380tr_send_packet; + dev->get_stats = tms380tr_get_stats; + dev->set_multicast_list = &tms380tr_set_multicast_list; + dev->set_mac_address = tms380tr_set_mac_address; + + return 0; +} + #ifdef MODULE -static struct net_device* dev_tms380tr[TMS380TR_MAX_ADAPTERS]; -static int io[TMS380TR_MAX_ADAPTERS] = { 0, 0 }; -static int irq[TMS380TR_MAX_ADAPTERS] = { 0, 0 }; -static int mem[TMS380TR_MAX_ADAPTERS] = { 0, 0 }; +EXPORT_SYMBOL(tms380tr_open); +EXPORT_SYMBOL(tms380tr_close); +EXPORT_SYMBOL(tms380tr_interrupt); +EXPORT_SYMBOL(tmsdev_init); +EXPORT_SYMBOL(tms380tr_wait); -MODULE_PARM(io, "1-" __MODULE_STRING(TMS380TR_MAX_ADAPTERS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(TMS380TR_MAX_ADAPTERS) "i"); -MODULE_PARM(mem, "1-" __MODULE_STRING(TMS380TR_MAX_ADAPTERS) "i"); +struct module *TMS380_module = NULL; int init_module(void) { - int i; - - for(i = 0; i < TMS380TR_MAX_ADAPTERS; i++) - { - irq[i] = 0; - mem[i] = 0; - dev_tms380tr[i] = NULL; - dev_tms380tr[i] = init_trdev(dev_tms380tr[i], 0); - if(dev_tms380tr[i] == NULL) - return (-ENOMEM); - - dev_tms380tr[i]->base_addr = io[i]; - dev_tms380tr[i]->irq = irq[i]; - dev_tms380tr[i]->mem_start = mem[i]; - dev_tms380tr[i]->init = &tms380tr_probe; - - if(register_trdev(dev_tms380tr[i]) != 0) - { - kfree_s(dev_tms380tr[i], sizeof(struct net_device)); - dev_tms380tr[i] = NULL; - if(i == 0) - { - printk("tms380tr: register_trdev() returned non-zero.\n"); - return (-EIO); - } - else - return (0); - } - - } - - return (0); + printk("%s", version); + + TMS380_module = &__this_module; + return 0; } void cleanup_module(void) { - int i; - - for(i = 0; i < TMS380TR_MAX_ADAPTERS; i++) - { - if(dev_tms380tr[i]) - { - unregister_trdev(dev_tms380tr[i]); - release_region(dev_tms380tr[i]->base_addr, TMS380TR_IO_EXTENT); - if(dev_tms380tr[i]->irq) - free_irq(dev_tms380tr[i]->irq, dev_tms380tr[i]); - if(dev_tms380tr[i]->dma > 0) - free_dma(dev_tms380tr[i]->dma); - if(dev_tms380tr[i]->priv) - kfree_s(dev_tms380tr[i]->priv, sizeof(struct net_local)); - kfree_s(dev_tms380tr[i], sizeof(struct net_device)); - dev_tms380tr[i] = NULL; - } - } + TMS380_module = NULL; } -#endif /* MODULE */ +#endif + + +/* + * Local variables: + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tms380tr.c" + * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tms380tr.c" + * c-set-style "K&R" + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h index 7896be0a0..f387de814 100644 --- a/drivers/net/tokenring/tms380tr.h +++ b/drivers/net/tokenring/tms380tr.h @@ -1,7 +1,9 @@ -/* tms380tr.h: TI TMS380 Token Ring driver for Linux +/* + * tms380tr.h: TI TMS380 Token Ring driver for Linux * * Authors: * - Christoph Goos <cgoos@syskonnect.de> + * - Adam Fritzler <mid@auk.cx> */ #ifndef __LINUX_TMS380TR_H @@ -9,6 +11,13 @@ #ifdef __KERNEL__ +/* module prototypes */ +int tms380tr_open(struct net_device *dev); +int tms380tr_close(struct net_device *dev); +void tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs); +int tmsdev_init(struct net_device *dev); +void tms380tr_wait(unsigned long time); + #define TMS380TR_MAX_ADAPTERS 7 #define SEND_TIMEOUT 10*HZ @@ -30,9 +39,6 @@ /* -------------------------------------------------------------- */ /*------------------------------------------------------------------*/ -/* Swap bytes of a word. */ -#define SWAPB(x) (((unsigned short)((x) << 8)) | ((unsigned short)((x) >> 8))) - /* Swap words of a long. */ #define SWAPW(x) (((x) << 16) | ((x) >> 16)) @@ -51,24 +57,34 @@ /* Token ring adapter I/O addresses for normal mode. */ -#define SIFDAT 0L /* SIF/DMA data. */ -#define SIFINC 2L /* IO Word data with auto increment. */ -#define SIFINH 3L /* IO Byte data with auto increment. */ -#define SIFADR 4L /* SIF/DMA Address. */ -#define SIFCMD 6L /* SIF Command. */ -#define SIFSTS 6L /* SIF Status. */ -#define SIFACL 8L /* SIF Adapter Control Register. */ -#define SIFADD 10L /* SIF/DMA Address. */ -#define SIFADX 12L -#define DMALEN 14L /* SIF DMA length. */ -#define POSREG 16L /* Adapter Program Option Select (POS) + +/* + * The SIF registers. Common to all adapters. + */ +/* Basic SIF (SRSX = 0) */ +#define SIFDAT 0x00 /* SIF/DMA data. */ +#define SIFINC 0x02 /* IO Word data with auto increment. */ +#define SIFINH 0x03 /* IO Byte data with auto increment. */ +#define SIFADR 0x04 /* SIF/DMA Address. */ +#define SIFCMD 0x06 /* SIF Command. */ +#define SIFSTS 0x06 /* SIF Status. */ + +/* "Extended" SIF (SRSX = 1) */ +#define SIFACL 0x08 /* SIF Adapter Control Register. */ +#define SIFADD 0x0a /* SIF/DMA Address. -- 0x0a */ +#define SIFADX 0x0c /* 0x0c */ +#define DMALEN 0x0e /* SIF DMA length. -- 0x0e */ + +/* + * POS Registers. Only for ISA Adapters. + */ +#define POSREG 0x10 /* Adapter Program Option Select (POS) * Register: base IO address + 16 byte. */ #define POSREG_2 24L /* only for TR4/16+ adapter - * base IO address + 24 byte. + * base IO address + 24 byte. -- 0x18 */ - /* SIFCMD command codes (high-low) */ #define CMD_INTERRUPT_ADAPTER 0x8000 /* Cause internal adapter interrupt */ #define CMD_ADAPTER_RESET 0x4000 /* Hardware reset of adapter */ @@ -118,8 +134,13 @@ * (1/0): can be written if ACL_ARESET * is zero. */ -#define ACL_SPEED4 0x0003 -#define ACL_SPEED16 0x0001 +#define ACL_PEN 0x0004 + +#define ACL_NSELOUT0 0x0002 +#define ACL_NSELOUT1 0x0001 /* NSELOUTx have a card-specific + * meaning for setting ring speed. + */ + #define PS_DMA_MASK (ACL_SWHRQ | ACL_PSDMAEN) @@ -145,69 +166,72 @@ /* Interrupt Codes (only MAC IRQs) */ -#define STS_IRQ_ADAPTER_CHECK 0x0000 /* unrecoverable hardware or +#define STS_IRQ_ADAPTER_CHECK 0x0000 /* unrecoverable hardware or * software error. */ -#define STS_IRQ_RING_STATUS 0x0004 /* SSB is updated with ring status. */ -#define STS_IRQ_SCB_CLEAR 0x0006 /* SCB clear, following an +#define STS_IRQ_RING_STATUS 0x0004 /* SSB is updated with ring status. */ +#define STS_IRQ_LLC_STATUS 0x0005 /* Not used in MAC-only microcode */ +#define STS_IRQ_SCB_CLEAR 0x0006 /* SCB clear, following an * SCB_REQUEST IRQ. */ -#define STS_IRQ_COMMAND_STATUS 0x0008 /* SSB is updated with command +#define STS_IRQ_TIMER 0x0007 /* Not normally used in MAC ucode */ +#define STS_IRQ_COMMAND_STATUS 0x0008 /* SSB is updated with command * status. */ -#define STS_IRQ_RECEIVE_STATUS 0x000A /* SSB is updated with receive +#define STS_IRQ_RECEIVE_STATUS 0x000A /* SSB is updated with receive * status. */ -#define STS_IRQ_TRANSMIT_STATUS 0x000C /* SSB is updated with transmit +#define STS_IRQ_TRANSMIT_STATUS 0x000C /* SSB is updated with transmit * status */ -#define STS_IRQ_MASK 0x000F /* = STS_ERROR_MASK. */ +#define STS_IRQ_RECEIVE_PENDING 0x000E /* Not used in MAC-only microcode */ +#define STS_IRQ_MASK 0x000F /* = STS_ERROR_MASK. */ /* TRANSMIT_STATUS completion code: (SSB.Parm[0]) */ -#define COMMAND_COMPLETE 0x0080 /* TRANSMIT command completed +#define COMMAND_COMPLETE 0x0080 /* TRANSMIT command completed * (avoid this!) issue another transmit * to send additional frames. */ -#define FRAME_COMPLETE 0x0040 /* Frame has been transmitted; +#define FRAME_COMPLETE 0x0040 /* Frame has been transmitted; * INTERRUPT_FRAME bit was set in the * CSTAT request; indication of possibly * more than one frame transmissions! * SSB.Parm[0-1]: 32 bit pointer to * TPL of last frame. */ -#define LIST_ERROR 0x0020 /* Error in one of the TPLs that +#define LIST_ERROR 0x0020 /* Error in one of the TPLs that * compose the frame; TRANSMIT - * terminated; Parm[1-2]: 32 bit pointer + * terminated; Parm[1-2]: 32bit pointer * to TPL which starts the error * frame; error details in bits 8-13. * (14?) */ -#define FRAME_SIZE_ERROR 0x8000 /* FRAME_SIZE does not equal the sum of +#define FRAME_SIZE_ERROR 0x8000 /* FRAME_SIZE does not equal the sum of * the valid DATA_COUNT fields; * FRAME_SIZE less than header plus * information field. (15 bytes + * routing field) Or if FRAME_SIZE * was specified as zero in one list. */ -#define TX_THRESHOLD 0x4000 /* FRAME_SIZE greater than (BUFFER_SIZE +#define TX_THRESHOLD 0x4000 /* FRAME_SIZE greater than (BUFFER_SIZE * - 9) * TX_BUF_MAX. */ -#define ODD_ADDRESS 0x2000 /* Odd forward pointer value is +#define ODD_ADDRESS 0x2000 /* Odd forward pointer value is * read on a list without END_FRAME * indication. */ -#define FRAME_ERROR 0x1000 /* START_FRAME bit is (not) anticipated, +#define FRAME_ERROR 0x1000 /* START_FRAME bit (not) anticipated, * but (not) set. */ -#define ACCESS_PRIORITY_ERROR 0x0800 /* Access priority requested has not +#define ACCESS_PRIORITY_ERROR 0x0800 /* Access priority requested has not * been allowed. */ -#define UNENABLED_MAC_FRAME 0x0400 /* MAC frame has source class of zero +#define UNENABLED_MAC_FRAME 0x0400 /* MAC frame has source class of zero * or MAC frame PCF ATTN field is * greater than one. */ -#define ILLEGAL_FRAME_FORMAT 0x0200 /* Bit 0 or FC field was set to one. */ +#define ILLEGAL_FRAME_FORMAT 0x0200 /* Bit 0 or FC field was set to one. */ /* @@ -222,98 +246,98 @@ * * The following defines the command code bits and the command queue: */ -#define OC_OPEN 0x0001 /* OPEN command */ -#define OC_TRANSMIT 0x0002 /* TRANSMIT command */ -#define OC_TRANSMIT_HALT 0x0004 /* TRANSMIT_HALT command */ -#define OC_RECEIVE 0x0008 /* RECEIVE command */ -#define OC_CLOSE 0x0010 /* CLOSE command */ -#define OC_SET_GROUP_ADDR 0x0020 /* SET_GROUP_ADDR command */ -#define OC_SET_FUNCT_ADDR 0x0040 /* SET_FUNCT_ADDR command */ -#define OC_READ_ERROR_LOG 0x0080 /* READ_ERROR_LOG command */ -#define OC_READ_ADAPTER 0x0100 /* READ_ADAPTER command */ -#define OC_MODIFY_OPEN_PARMS 0x0400 /* MODIFY_OPEN_PARMS command */ -#define OC_RESTORE_OPEN_PARMS 0x0800 /* RESTORE_OPEN_PARMS command */ -#define OC_SET_FIRST_16_GROUP 0x1000 /* SET_FIRST_16_GROUP command */ -#define OC_SET_BRIDGE_PARMS 0x2000 /* SET_BRIDGE_PARMS command */ -#define OC_CONFIG_BRIDGE_PARMS 0x4000 /* CONFIG_BRIDGE_PARMS command */ - -#define OPEN 0x0300 /* C: open command. S: completion. */ -#define TRANSMIT 0x0400 /* C: transmit command. S: completion +#define OC_OPEN 0x0001 /* OPEN command */ +#define OC_TRANSMIT 0x0002 /* TRANSMIT command */ +#define OC_TRANSMIT_HALT 0x0004 /* TRANSMIT_HALT command */ +#define OC_RECEIVE 0x0008 /* RECEIVE command */ +#define OC_CLOSE 0x0010 /* CLOSE command */ +#define OC_SET_GROUP_ADDR 0x0020 /* SET_GROUP_ADDR command */ +#define OC_SET_FUNCT_ADDR 0x0040 /* SET_FUNCT_ADDR command */ +#define OC_READ_ERROR_LOG 0x0080 /* READ_ERROR_LOG command */ +#define OC_READ_ADAPTER 0x0100 /* READ_ADAPTER command */ +#define OC_MODIFY_OPEN_PARMS 0x0400 /* MODIFY_OPEN_PARMS command */ +#define OC_RESTORE_OPEN_PARMS 0x0800 /* RESTORE_OPEN_PARMS command */ +#define OC_SET_FIRST_16_GROUP 0x1000 /* SET_FIRST_16_GROUP command */ +#define OC_SET_BRIDGE_PARMS 0x2000 /* SET_BRIDGE_PARMS command */ +#define OC_CONFIG_BRIDGE_PARMS 0x4000 /* CONFIG_BRIDGE_PARMS command */ + +#define OPEN 0x0300 /* C: open command. S: completion. */ +#define TRANSMIT 0x0400 /* C: transmit command. S: completion * status. (reject: COMMAND_REJECT if * adapter not opened, TRANSMIT already * issued or address passed in the SCB * not word aligned) */ -#define TRANSMIT_HALT 0x0500 /* C: interrupt TX TPL chain; if no +#define TRANSMIT_HALT 0x0500 /* C: interrupt TX TPL chain; if no * TRANSMIT command issued, the command - * is ignored. (completion with TRANSMIT + * is ignored (completion with TRANSMIT * status (0x0400)!) */ -#define RECEIVE 0x0600 /* C: receive command. S: completion +#define RECEIVE 0x0600 /* C: receive command. S: completion * status. (reject: COMMAND_REJECT if * adapter not opened, RECEIVE already * issued or address passed in the SCB * not word aligned) */ -#define CLOSE 0x0700 /* C: close adapter. S: completion. +#define CLOSE 0x0700 /* C: close adapter. S: completion. * (COMMAND_REJECT if adapter not open) */ -#define SET_GROUP_ADDR 0x0800 /* C: alter adapter group address after - * OPEN. S: completion. (COMMAND_REJECT +#define SET_GROUP_ADDR 0x0800 /* C: alter adapter group address after + * OPEN. S: completion. (COMMAND_REJECT * if adapter not open) */ -#define SET_FUNCT_ADDR 0x0900 /* C: alter adapter functional address +#define SET_FUNCT_ADDR 0x0900 /* C: alter adapter functional address * after OPEN. S: completion. * (COMMAND_REJECT if adapter not open) */ -#define READ_ERROR_LOG 0x0A00 /* C: read adapter error counters. +#define READ_ERROR_LOG 0x0A00 /* C: read adapter error counters. * S: completion. (command ignored * if adapter not open!) */ -#define READ_ADAPTER 0x0B00 /* C: read data from adapter memory. +#define READ_ADAPTER 0x0B00 /* C: read data from adapter memory. * (important: after init and before * open!) S: completion. (ADAPTER_CHECK * interrupt if undefined storage area * read) */ -#define MODIFY_OPEN_PARMS 0x0D00 /* C: modify some adapter operational +#define MODIFY_OPEN_PARMS 0x0D00 /* C: modify some adapter operational * parameters. (bit correspondend to * WRAP_INTERFACE is ignored) * S: completion. (reject: * COMMAND_REJECT) */ -#define RESTORE_OPEN_PARMS 0x0E00 /* C: modify some adapter operational +#define RESTORE_OPEN_PARMS 0x0E00 /* C: modify some adapter operational * parameters. (bit correspondend * to WRAP_INTERFACE is ignored) * S: completion. (reject: * COMMAND_REJECT) */ -#define SET_FIRST_16_GROUP 0x0F00 /* C: alter the first two bytes in +#define SET_FIRST_16_GROUP 0x0F00 /* C: alter the first two bytes in * adapter group address. * S: completion. (reject: * COMMAND_REJECT) */ -#define SET_BRIDGE_PARMS 0x1000 /* C: values and conditions for the +#define SET_BRIDGE_PARMS 0x1000 /* C: values and conditions for the * adapter hardware to use when frames * are copied for forwarding. * S: completion. (reject: * COMMAND_REJECT) */ -#define CONFIG_BRIDGE_PARMS 0x1100 /* C: .. +#define CONFIG_BRIDGE_PARMS 0x1100 /* C: .. * S: completion. (reject: * COMMAND_REJECT) */ -#define SPEED_4 4 -#define SPEED_16 16 /* Default transmission speed */ +#define SPEED_4 4 +#define SPEED_16 16 /* Default transmission speed */ /* Initialization Parameter Block (IPB); word alignment necessary! */ -#define BURST_SIZE 0x0018 /* Default burst size */ -#define BURST_MODE 0x9F00 /* Burst mode enable */ -#define DMA_RETRIES 0x0505 /* Magic DMA retry number... */ +#define BURST_SIZE 0x0018 /* Default burst size */ +#define BURST_MODE 0x9F00 /* Burst mode enable */ +#define DMA_RETRIES 0x0505 /* Magic DMA retry number... */ -#define CYCLE_TIME 3 /* Default AT-bus cycle time: 500 ns +#define CYCLE_TIME 3 /* Default AT-bus cycle time: 500 ns * (later adapter version: fix cycle time!) */ #define LINE_SPEED_BIT 0x80 @@ -327,7 +351,7 @@ #define FOUR_SECONDS (ONE_SECOND_TICKS * 4) #define FIVE_SECONDS (ONE_SECOND_TICKS * 5) -#define BUFFER_SIZE 2048 /* Buffers on Adapter */ +#define BUFFER_SIZE 2048 /* Buffers on Adapter */ #pragma pack(1) typedef struct { @@ -337,18 +361,18 @@ typedef struct { /* Interrupt vectors the adapter places on attached system bus. */ unsigned char CMD_Status_IV; /* Interrupt vector: command status. */ - unsigned char TX_IV; /* Interrupt vector: transmit. */ - unsigned char RX_IV; /* Interrupt vector: receive. */ + unsigned char TX_IV; /* Interrupt vector: transmit. */ + unsigned char RX_IV; /* Interrupt vector: receive. */ unsigned char Ring_Status_IV; /* Interrupt vector: ring status. */ - unsigned char SCB_Clear_IV; /* Interrupt vector: SCB clear. */ + unsigned char SCB_Clear_IV; /* Interrupt vector: SCB clear. */ unsigned char Adapter_CHK_IV; /* Interrupt vector: adapter check. */ unsigned short RX_Burst_Size; /* Max. number of transfer cycles. */ unsigned short TX_Burst_Size; /* During DMA burst; even value! */ - unsigned short DMA_Abort_Thrhld; /* Number of DMA retries. */ + unsigned short DMA_Abort_Thrhld;/* Number of DMA retries. */ - unsigned long SCB_Addr; /* SCB address: even, word aligned, high-low. */ - unsigned long SSB_Addr; /* SSB address: even, word aligned, high-low. */ + unsigned long SCB_Addr; /* SCB address: even, word aligned, high-low */ + unsigned long SSB_Addr; /* SSB address: even, word aligned, high-low */ } IPB, *IPB_Ptr; #pragma pack() @@ -361,10 +385,10 @@ typedef struct { #define RPL_SIZE 14 /* (with TI firmware v2.26 handling * up to nine fragments possible) */ -#define TX_BUF_MIN 20 /* ??? (Stephan: calculation with */ -#define TX_BUF_MAX 40 /* BUFFER_SIZE and MAX_FRAME_SIZE) ??? +#define TX_BUF_MIN 20 /* ??? (Stephan: calculation with */ +#define TX_BUF_MAX 40 /* BUFFER_SIZE and MAX_FRAME_SIZE) ??? */ -#define DISABLE_EARLY_TOKEN_RELEASE 0x1000 +#define DISABLE_EARLY_TOKEN_RELEASE 0x1000 /* OPEN Options (high-low) */ #define WRAP_INTERFACE 0x0080 /* Inserting omitted for test @@ -372,51 +396,52 @@ typedef struct { * as receive data. (usefull for * testing; change: CLOSE necessary) */ -#define DISABLE_HARD_ERROR 0x0040 /* On HARD_ERROR & TRANSMIT_BEACON +#define DISABLE_HARD_ERROR 0x0040 /* On HARD_ERROR & TRANSMIT_BEACON * no RING.STATUS interrupt. */ -#define DISABLE_SOFT_ERROR 0x0020 /* On SOFT_ERROR, no RING.STATUS +#define DISABLE_SOFT_ERROR 0x0020 /* On SOFT_ERROR, no RING.STATUS * interrupt. */ -#define PASS_ADAPTER_MAC_FRAMES 0x0010 /* Passing unsupported MAC frames +#define PASS_ADAPTER_MAC_FRAMES 0x0010 /* Passing unsupported MAC frames * to system. */ -#define PASS_ATTENTION_FRAMES 0x0008 /* All changed attention MAC frames are +#define PASS_ATTENTION_FRAMES 0x0008 /* All changed attention MAC frames are * passed to the system. */ -#define PAD_ROUTING_FIELD 0x0004 /* Routing field is padded to 18 +#define PAD_ROUTING_FIELD 0x0004 /* Routing field is padded to 18 * bytes. */ -#define FRAME_HOLD 0x0002 /* Adapter waits for entire frame before +#define FRAME_HOLD 0x0002 /*Adapter waits for entire frame before * initiating DMA transfer; otherwise: * DMA transfer initiation if internal * buffer filled. */ -#define CONTENDER 0x0001 /* Adapter participates in the monitor +#define CONTENDER 0x0001 /* Adapter participates in the monitor * contention process. */ -#define PASS_BEACON_MAC_FRAMES 0x8000 /* Adapter passes beacon MAC frames +#define PASS_BEACON_MAC_FRAMES 0x8000 /* Adapter passes beacon MAC frames * to the system. */ -#define EARLY_TOKEN_RELEASE 0x1000 /* Only valid in 16 Mbps operation; +#define EARLY_TOKEN_RELEASE 0x1000 /* Only valid in 16 Mbps operation; * 0 = ETR. (no effect in 4 Mbps * operation) */ -#define COPY_ALL_MAC_FRAMES 0x0400 /* All MAC frames are copied to +#define COPY_ALL_MAC_FRAMES 0x0400 /* All MAC frames are copied to * the system. (after OPEN: duplicate * address test (DAT) MAC frame is * first received frame copied to the * system) */ -#define COPY_ALL_NON_MAC_FRAMES 0x0200 /* All non MAC frames are copied to +#define COPY_ALL_NON_MAC_FRAMES 0x0200 /* All non MAC frames are copied to * the system. */ -#define PASS_FIRST_BUF_ONLY 0x0100 /* Passes only first internal buffer +#define PASS_FIRST_BUF_ONLY 0x0100 /* Passes only first internal buffer * of each received frame; FrameSize * of RPLs must contain internal * BUFFER_SIZE bits for promiscous mode. */ -#define ENABLE_FULL_DUPLEX_SELECTION 0x2000 /* Enable the use of full-duplex +#define ENABLE_FULL_DUPLEX_SELECTION 0x2000 + /* Enable the use of full-duplex * settings with bits in byte 22 in * ocpl. (new feature in firmware * version 3.09) @@ -434,7 +459,7 @@ typedef struct { * fragments following. */ -#define ISA_MAX_ADDRESS 0x00ffffff +#define ISA_MAX_ADDRESS 0x00ffffff #pragma pack(1) typedef struct { @@ -1031,15 +1056,6 @@ struct s_RPL { /* Receive Parameter List */ int RPLIndex; }; -#define TMS_ISA 1 -#define TMS_PCI 2 -struct cardinfo_table { - int type; /* 1 = ISA, 2 = PCI */ - int vendor_id; - int device_id; - char *name; -}; - /* Information that need to be kept for each board. */ typedef struct net_local { #pragma pack(1) @@ -1094,7 +1110,7 @@ typedef struct net_local { struct tr_statistics MacStat; /* MAC statistics structure */ - struct cardinfo_table *CardType; + unsigned long dmalimit; /* the max DMA address (ie, ISA) */ struct timer_list timer; @@ -1103,6 +1119,13 @@ typedef struct net_local { INTPTRS intptrs; /* Internal adapter pointer. Must be read * before OPEN command. */ + unsigned short (*setnselout)(struct net_device *); + unsigned short (*sifreadb)(struct net_device *, unsigned short); + void (*sifwriteb)(struct net_device *, unsigned short, unsigned short); + unsigned short (*sifreadw)(struct net_device *, unsigned short); + void (*sifwritew)(struct net_device *, unsigned short, unsigned short); + + void *tmspriv; } NET_LOCAL; #endif /* __KERNEL__ */ diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c new file mode 100644 index 000000000..ffcfab931 --- /dev/null +++ b/drivers/net/tokenring/tmspci.c @@ -0,0 +1,336 @@ +/* + * tmspci.c: A generic network driver for TMS380-based PCI token ring cards. + * + * Written 1999 by Adam Fritzler + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * This driver module supports the following cards: + * - SysKonnect TR4/16(+) PCI (SK-4590) + * - SysKonnect TR4/16 PCI (SK-4591) + * - Compaq TR 4/16 PCI + * - Thomas-Conrad TC4048 4/16 PCI + * - 3Com 3C339 Token Link Velocity + * + * Maintainer(s): + * AF Adam Fritzler mid@auk.cx + * + * Modification History: + * 30-Dec-99 AF Split off from the tms380tr driver. + * 22-Jan-00 AF Updated to use indirect read/writes + * + * TODO: + * 1. See if we can use MMIO instead of port accesses + * + */ +static const char *version = "tmspci.c: v1.01 22/01/2000 by Adam Fritzler\n"; + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> + +#include <linux/netdevice.h> +#include <linux/trdevice.h> +#include "tms380tr.h" + +#define TMS_PCI_IO_EXTENT 32 + +struct cardinfo_table { + int vendor_id; /* PCI info */ + int device_id; + int registeroffset; /* SIF offset from dev->base_addr */ + unsigned char nselout[2]; /* NSELOUT vals for 4mb([0]) and 16mb([1]) */ + char *name; +}; + +struct cardinfo_table probelist[] = { + { 0, 0, + 0x0000, {0x00, 0x00}, "Unknown TMS380 Token Ring Adapter"}, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, + 0x0000, {0x03, 0x01}, "Compaq 4/16 TR PCI"}, + { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, + 0x0000, {0x03, 0x01}, "SK NET TR 4/16 PCI"}, + { PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, + 0x0000, {0x03, 0x01}, "Thomas-Conrad TC4048 PCI 4/16"}, + { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C339, + 0x0000, {0x03, 0x01}, "3Com Token Link Velocity"}, + { 0, 0, 0, {0x00, 0x00}, NULL} +}; + +int tms_pci_probe(void); +static int tms_pci_open(struct net_device *dev); +static int tms_pci_close(struct net_device *dev); +static void tms_pci_read_eeprom(struct net_device *dev); +static unsigned short tms_pci_setnselout_pins(struct net_device *dev); + +static unsigned short tms_pci_sifreadb(struct net_device *dev, unsigned short reg) +{ + return inb(dev->base_addr + reg); +} + +static unsigned short tms_pci_sifreadw(struct net_device *dev, unsigned short reg) +{ + return inw(dev->base_addr + reg); +} + +static void tms_pci_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) +{ + outb(val, dev->base_addr + reg); +} + +static void tms_pci_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) +{ + outw(val, dev->base_addr + reg); +} + +struct tms_pci_card { + struct net_device *dev; + struct pci_dev *pci_dev; + struct cardinfo_table *cardinfo; + struct tms_pci_card *next; +}; +static struct tms_pci_card *tms_pci_card_list = NULL; + + +struct cardinfo_table * __init tms_pci_getcardinfo(unsigned short vendor, + unsigned short device) +{ + int cur; + for (cur = 1; probelist[cur].name != NULL; cur++) { + if ((probelist[cur].vendor_id == vendor) && + (probelist[cur].device_id == device)) + return &probelist[cur]; + } + + return NULL; +} + +int __init tms_pci_probe(void) +{ + static int versionprinted = 0; + struct pci_dev *pdev = NULL ; + struct net_device *dev; + struct net_local *tp; + int i; + + if (!pci_present()) + return (-1); /* No PCI present. */ + + while ( (pdev=pci_find_class(PCI_CLASS_NETWORK_TOKEN_RING<<8, pdev))) { + unsigned int pci_irq_line; + unsigned long pci_ioaddr; + struct tms_pci_card *card; + struct cardinfo_table *cardinfo; + + if ((cardinfo = + tms_pci_getcardinfo(pdev->vendor, pdev->device)) == NULL) + continue; + + if (versionprinted++ == 0) + printk("%s", version); + + pci_enable_device(pdev); + + /* Remove I/O space marker in bit 0. */ + pci_irq_line = pdev->irq; + pci_ioaddr = pdev->resource[0].start ; + + if(check_region(pci_ioaddr, TMS_PCI_IO_EXTENT)) + continue; + + /* At this point we have found a valid card. */ + + dev = init_trdev(NULL, 0); + + request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, cardinfo->name); + if(request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ, + cardinfo->name, dev)) { + release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); + continue; /*return (-ENODEV);*/ /* continue; ?? */ + } + + /* + if (load_tms380_module("tmspci.c")) { + return 0; + } + */ + + pci_ioaddr &= ~3 ; + dev->base_addr = pci_ioaddr; + dev->irq = pci_irq_line; + dev->dma = 0; + + printk("%s: %s\n", dev->name, cardinfo->name); + printk("%s: IO: %#4lx IRQ: %d\n", + dev->name, dev->base_addr, dev->irq); + /* + * Some cards have their TMS SIF registers offset from + * their given base address. Account for that here. + */ + dev->base_addr += cardinfo->registeroffset; + + tms_pci_read_eeprom(dev); + + printk("%s: Ring Station Address: ", dev->name); + printk("%2.2x", dev->dev_addr[0]); + for (i = 1; i < 6; i++) + printk(":%2.2x", dev->dev_addr[i]); + printk("\n"); + + if (tmsdev_init(dev)) { + printk("%s: unable to get memory for dev->priv.\n", dev->name); + return 0; + } + + tp = (struct net_local *)dev->priv; + tp->dmalimit = 0; /* XXX: should be the max PCI32 DMA max */ + tp->setnselout = tms_pci_setnselout_pins; + + tp->sifreadb = tms_pci_sifreadb; + tp->sifreadw = tms_pci_sifreadw; + tp->sifwriteb = tms_pci_sifwriteb; + tp->sifwritew = tms_pci_sifwritew; + + memcpy(tp->ProductID, cardinfo->name, PROD_ID_SIZE + 1); + + tp->tmspriv = cardinfo; + + dev->open = tms_pci_open; + dev->stop = tms_pci_close; + + if (register_trdev(dev) == 0) { + /* Enlist in the card list */ + card = kmalloc(sizeof(struct tms_pci_card), GFP_KERNEL); + card->next = tms_pci_card_list; + tms_pci_card_list = card; + card->dev = dev; + card->pci_dev = pdev; + card->cardinfo = cardinfo; + } else { + printk("%s: register_trdev() returned non-zero.\n", dev->name); + kfree(dev->priv); + kfree(dev); + return -1; + } + } + + if (tms_pci_card_list) + return 0; + return (-1); +} + +/* + * Reads MAC address from adapter RAM, which should've read it from + * the onboard ROM. + * + * Calling this on a board that does not support it can be a very + * dangerous thing. The Madge board, for instance, will lock your + * machine hard when this is called. Luckily, its supported in a + * seperate driver. --ASF + */ +static void tms_pci_read_eeprom(struct net_device *dev) +{ + int i; + + /* Address: 0000:0000 */ + tms_pci_sifwritew(dev, 0, SIFADX); + tms_pci_sifwritew(dev, 0, SIFADR); + + /* Read six byte MAC address data */ + dev->addr_len = 6; + for(i = 0; i < 6; i++) + dev->dev_addr[i] = tms_pci_sifreadw(dev, SIFINC) >> 8; +} + +unsigned short tms_pci_setnselout_pins(struct net_device *dev) +{ + unsigned short val = 0; + struct net_local *tp = (struct net_local *)dev->priv; + struct cardinfo_table *cardinfo = (struct cardinfo_table *)tp->tmspriv; + + if(tp->DataRate == SPEED_4) + val |= cardinfo->nselout[0]; /* Set 4Mbps */ + else + val |= cardinfo->nselout[1]; /* Set 16Mbps */ + return val; +} + +static int tms_pci_open(struct net_device *dev) +{ + tms380tr_open(dev); + MOD_INC_USE_COUNT; + return 0; +} + +static int tms_pci_close(struct net_device *dev) +{ + tms380tr_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +#ifdef MODULE + +int init_module(void) +{ + /* Probe for cards. */ + if (tms_pci_probe()) { + printk(KERN_NOTICE "tmspci.c: No cards found.\n"); + } + /* lock_tms380_module(); */ + return (0); +} + +void cleanup_module(void) +{ + struct net_device *dev; + struct tms_pci_card *this_card; + + while (tms_pci_card_list) { + dev = tms_pci_card_list->dev; + + /* + * If we used a register offset, revert here. + */ + if (dev->priv) + { + struct net_local *tp; + struct cardinfo_table *cardinfo; + + tp = (struct net_local *)dev->priv; + cardinfo = (struct cardinfo_table *)tp->tmspriv; + + dev->base_addr -= cardinfo->registeroffset; + } + unregister_netdev(dev); + release_region(dev->base_addr, TMS_PCI_IO_EXTENT); + free_irq(dev->irq, dev); + kfree(dev->priv); + kfree(dev); + this_card = tms_pci_card_list; + tms_pci_card_list = this_card->next; + kfree(this_card); + } + /* unlock_tms380_module(); */ +} +#endif /* MODULE */ + + +/* + * Local variables: + * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tmspci.c" + * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tmspci.c" + * c-set-style "K&R" + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/wan/Config.in b/drivers/net/wan/Config.in index 503854a0f..962e171fa 100644 --- a/drivers/net/wan/Config.in +++ b/drivers/net/wan/Config.in @@ -34,10 +34,11 @@ if [ "$CONFIG_WAN" = "y" ]; then if [ "$CONFIG_WAN_ROUTER_DRIVERS" = "y" ]; then dep_tristate ' Sangoma WANPIPE(tm) multiprotocol cards' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_ROUTER_DRIVERS if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then - int 'Maximum number of cards' CONFIG_WANPIPE_CARDS 1 - bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 + int ' Maximum number of cards' CONFIG_WANPIPE_CARDS 1 + bool ' WANPIPE Cisco HDLC support' CONFIG_WANPIPE_CHDLC bool ' WANPIPE Frame Relay support' CONFIG_WANPIPE_FR bool ' WANPIPE PPP support' CONFIG_WANPIPE_PPP + bool ' WANPIPE X.25 support' CONFIG_WANPIPE_X25 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Cyclom 2X(tm) cards (EXPERIMENTAL)' CONFIG_CYCLADES_SYNC $CONFIG_WAN_ROUTER_DRIVERS diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 73060f5b9..67f6bb59b 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -102,6 +102,9 @@ ifeq ($(CONFIG_VENDOR_SANGOMA),y) ifeq ($(CONFIG_WANPIPE_X25),y) L_OBJS += sdla_x25.o endif + ifeq ($(CONFIG_WANPIPE_CHDLC),y) + L_OBJS += sdla_chdlc.o + endif ifeq ($(CONFIG_WANPIPE_FR),y) L_OBJS += sdla_fr.o endif @@ -122,6 +125,9 @@ ifeq ($(CONFIG_VENDOR_SANGOMA),m) ifeq ($(CONFIG_WANPIPE_FR),y) WANPIPE_OBJS += sdla_fr.o endif + ifeq ($(CONFIG_WANPIPE_CHDLC),y) + WANPIPE_OBJS += sdla_chdlc.o + endif ifeq ($(CONFIG_WANPIPE_PPP),y) WANPIPE_OBJS += sdla_ppp.o endif diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index b9b72ddeb..188b06c97 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c @@ -13,6 +13,8 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* 2000/01/21 acme rename cyclomx_open to cyclomx_mod_inc_use_count +* and cyclomx_close to cyclomx_mod_dec_use_count * 2000/01/08 acme cleanup * 1999/11/06 acme cycx_down back to life (it needs to be * called to iounmap the dpmbase) @@ -49,7 +51,7 @@ MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver."); /* Defines & Macros */ #define DRV_VERSION 0 /* version number */ -#define DRV_RELEASE 5 /* release (minor version) number */ +#define DRV_RELEASE 6 /* release (minor version) number */ #define MAX_CARDS 1 /* max number of adapters */ #ifndef CONFIG_CYCLOMX_CARDS /* configurable option */ @@ -132,9 +134,9 @@ int __init cyclomx_init (void) err = register_wan_device(wandev); if (err) { - printk(KERN_ERR - "%s: %s registration failed with error %d!\n", - drvname, card->devname, err); + printk(KERN_ERR "%s: %s registration failed with " + "error %d!\n", + drvname, card->devname, err); break; } } @@ -238,7 +240,7 @@ static int setup (wan_device_t *wandev, wandev_conf_t *conf) /* Initialize WAN device data space */ wandev->irq = irq; wandev->dma = wandev->ioport = 0; - wandev->maddr = (unsigned long*)card->hw.dpmbase; + wandev->maddr = card->hw.dpmbase; wandev->msize = card->hw.dpmsize; wandev->hw_opt[2] = 0; wandev->hw_opt[3] = card->hw.fwid; @@ -338,7 +340,7 @@ static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs) * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's * defined more than once into the same kernel module. */ -void cyclomx_open (cycx_t *card) +void cyclomx_mod_inc_use_count (cycx_t *card) { ++card->open_cnt; MOD_INC_USE_COUNT; @@ -350,7 +352,7 @@ void cyclomx_open (cycx_t *card) * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's * defined more than once into the same kernel module. */ -void cyclomx_close (cycx_t *card) +void cyclomx_mod_dec_use_count (cycx_t *card) { --card->open_cnt; MOD_DEC_USE_COUNT; diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index e9156df92..e11c9bcfe 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -70,6 +70,7 @@ * 1998/12/26 acme Minimal debug code cleanup * 1998/08/08 acme Initial version. */ + #define CYCLOMX_X25_DEBUG 1 #include <linux/version.h> @@ -188,7 +189,6 @@ static void x25_dump_devs(wan_device_t *wandev); * * This routine is called by the main Cyclom 2X module during setup. At this * point adapter is completely initialized and X.25 firmware is running. - * o read firmware version (to make sure it's alive) * o configure adapter * o initialize protocol-specific fields of the adapter data space. * @@ -336,7 +336,8 @@ static int update (wan_device_t *wandev) * * Return: 0 o.k. * < 0 failure (channel will not be created) */ -static int new_if (wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf) +static int new_if (wan_device_t *wandev, struct net_device *dev, + wanif_conf_t *conf) { cycx_t *card = wandev->private; x25_channel_t *chan; @@ -507,7 +508,7 @@ static int if_open (struct net_device *dev) dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; - cyclomx_open(card); + cyclomx_mod_inc_use_count(card); return 0; } @@ -525,7 +526,7 @@ static int if_close (struct net_device *dev) if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING) chan_disconnect(dev); - cyclomx_close(card); + cyclomx_mod_dec_use_count(card); return 0; } diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 9cadf1e0b..29bedf8f9 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -1666,7 +1666,7 @@ int __init sdla_init(struct net_device *dev) return(0); } -int __init sdla_setup(void) +int __init sdla_c_setup(void) { printk("%s.\n", version); register_frad(devname); @@ -1680,7 +1680,7 @@ int init_module(void) { int result; - sdla_setup(); + sdla_c_setup(); if ((result = register_netdev(&sdla0)) != 0) return result; return 0; diff --git a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c new file mode 100644 index 000000000..3df910ea1 --- /dev/null +++ b/drivers/net/wan/sdla_chdlc.c @@ -0,0 +1,2785 @@ +/***************************************************************************** +* sdla_chdlc.c WANPIPE(tm) Multiprotocol WAN Link Driver. Cisco HDLC module. +* +* Authors: Nenad Corbic <ncorbic@sangoma.com> +* Gideon Hack +* +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. +* +* 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 the Free Software Foundation; either version +* 2 of the License, or (at your option) any later version. +* ============================================================================ +* Nov 20, 1999 Nenad Corbic Fixed zero length API bug. +* Sep 30, 1999 Nenad Corbic Fixed dynamic IP and route setup. +* Sep 23, 1999 Nenad Corbic Added SMP support, fixed tracing +* Sep 13, 1999 Nenad Corbic Split up Port 0 and 1 into separate devices. +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Oct 30, 1998 Jaspreet Singh Added Support for CHDLC API (HDLC STREAMING). +* Oct 28, 1998 Jaspreet Singh Added Support for Dual Port CHDLC. +* Aug 07, 1998 David Fong Initial version. +*****************************************************************************/ + +#include <linux/version.h> +#include <linux/kernel.h> /* printk(), and other useful stuff */ +#include <linux/stddef.h> /* offsetof(), etc. */ +#include <linux/errno.h> /* return codes */ +#include <linux/string.h> /* inline memset(), etc. */ +#include <linux/malloc.h> /* kmalloc(), kfree() */ +#include <linux/wanrouter.h> /* WAN router definitions */ +#include <linux/wanpipe.h> /* WANPIPE common user API definitions */ +#include <linux/if_arp.h> /* ARPHRD_* defines */ +#include <linux/inetdevice.h> +#include <asm/uaccess.h> +#include <linux/in.h> /* sockaddr_in */ +#include <linux/inet.h> +#include <linux/if.h> +#include <asm/byteorder.h> /* htons(), etc. */ +#include <linux/sdlapci.h> +#include <asm/io.h> + +#include <linux/sdla_chdlc.h> /* CHDLC firmware API definitions */ + +/****** Defines & Macros ****************************************************/ + +#ifdef _DEBUG_ +#define STATIC +#else +#define STATIC static +#endif + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x0001 +#define TMR_INT_ENABLED_UPDATE 0x0002 + +#define CHDLC_DFLT_DATA_LEN 1500 /* default MTU */ +#define CHDLC_HDR_LEN 1 + +#define IFF_POINTTOPOINT 0x10 + +#define WANPIPE 0x00 +#define API 0x01 +#define CHDLC_API 0x01 + +#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) + + +/******Data Structures*****************************************************/ + +/* This structure is placed in the private data area of the device structure. + * The card structure used to occupy the private area but now the following + * structure will incorporate the card structure along with CHDLC specific data + */ + +typedef struct chdlc_private_area +{ + sdla_t *card; + int TracingEnabled; /* For enabling Tracing */ + unsigned long curr_trace_addr; /* Used for Tracing */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + unsigned long base_addr_trace_buffer; + unsigned long end_addr_trace_buffer; + unsigned short number_trace_elements; + unsigned available_buffer_space; + unsigned long router_start_time; + unsigned char route_status; + unsigned char route_removed; + unsigned long tick_counter; /* For 5s timeout counter */ + unsigned long router_up_time; + u32 IP_address; /* IP addressing */ + u32 IP_netmask; + unsigned char mc; /* Mulitcast support on/off */ + unsigned short udp_pkt_lgth; /* udp packet processing */ + char udp_pkt_src; + char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; + unsigned short timer_int_enabled; + char update_comms_stats; /* updating comms stats */ + //FIXME: add driver stats as per frame relay! + +} chdlc_private_area_t; + +/* Route Status options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + + +/* variable for keeping track of enabling/disabling FT1 monitor status */ +static int rCount = 0; + +/* variable for tracking how many interfaces to open for WANPIPE on the + two ports */ + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +/****** Function Prototypes *************************************************/ +/* WAN link driver entry points. These are called by the WAN router module. */ +static int update (wan_device_t* wandev); +static int new_if (wan_device_t* wandev, struct net_device* dev, + wanif_conf_t* conf); +static int del_if (wan_device_t* wandev, struct net_device* dev); + +/* Network device interface */ +static int if_init (struct net_device* dev); +static int if_open (struct net_device* dev); +static int if_close (struct net_device* dev); +static int if_header (struct sk_buff* skb, struct net_device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len); +#ifdef LINUX_2_1 +static int if_rebuild_hdr (struct sk_buff *skb); +#else +static int if_rebuild_hdr (void* hdr, struct net_device* dev, unsigned long raddr, + struct sk_buff* skb); +#endif +static int if_send (struct sk_buff* skb, struct net_device* dev); +static struct enet_statistics* if_stats (struct net_device* dev); + +/* CHDLC Firmware interface functions */ +static int chdlc_configure (sdla_t* card, void* data); +static int chdlc_comm_enable (sdla_t* card); +static int chdlc_comm_disable (sdla_t* card); +static int chdlc_read_version (sdla_t* card, char* str); +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode); +static int chdlc_send (sdla_t* card, void* data, unsigned len); +static int chdlc_read_comm_err_stats (sdla_t* card); +static int chdlc_read_op_stats (sdla_t* card); + + +/* Miscellaneous CHDLC Functions */ +static int set_chdlc_config (sdla_t* card); +static void init_chdlc_tx_rx_buff( sdla_t* card, struct net_device *dev ); +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb); +static int process_chdlc_exception(sdla_t *card); +static int process_global_exception(sdla_t *card); +static int update_comms_stats(sdla_t* card, + chdlc_private_area_t* chdlc_priv_area); +static int configure_ip (sdla_t* card); +static int unconfigure_ip (sdla_t* card); +static void process_route(sdla_t *card); +static void port_set_state (sdla_t *card, int); + + +/* Interrupt handlers */ +static void wpc_isr (sdla_t* card); +static void rx_intr (sdla_t* card); +static void timer_intr(sdla_t *); + +/* Miscellaneous functions */ +static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, + struct sk_buff *skb); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static int intr_test( sdla_t* card, struct net_device *dev ); +static int udp_pkt_type( struct sk_buff *skb , sdla_t* card); +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, struct net_device* dev, + chdlc_private_area_t* chdlc_priv_area); +static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, + chdlc_private_area_t* chdlc_priv_area); +static unsigned short calc_checksum (char *, int); +static void s508_lock (sdla_t *card, unsigned long *smp_flags); +static void s508_unlock (sdla_t *card, unsigned long *smp_flags); + + +static int Intr_test_counter; +/****** Public Functions ****************************************************/ + +/*============================================================================ + * Cisco HDLC protocol initialization routine. + * + * This routine is called by the main WANPIPE module during setup. At this + * point adapter is completely initialized and firmware is running. + * o read firmware version (to make sure it's alive) + * o configure adapter + * o initialize protocol-specific fields of the adapter data space. + * + * Return: 0 o.k. + * < 0 failure. + */ +int wpc_init (sdla_t* card, wandev_conf_t* conf) +{ + unsigned char port_num; + int err; + unsigned long max_permitted_baud = 0; + + union + { + char str[80]; + } u; + volatile CHDLC_MAILBOX_STRUCT* mb; + CHDLC_MAILBOX_STRUCT* mb1; + unsigned long timeout; + + /* Verify configuration ID */ + if (conf->config_id != WANCONFIG_CHDLC) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", + card->devname, conf->config_id); + return -EINVAL; + } + + /* Find out which Port to use */ + if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){ + if (card->next){ + + if (conf->comm_port != card->next->u.c.comm_port){ + card->u.c.comm_port = conf->comm_port; + }else{ + printk(KERN_ERR "%s: ERROR - %s port used!\n", + card->wandev.name, PORT(conf->comm_port)); + return -EINVAL; + } + }else{ + card->u.c.comm_port = conf->comm_port; + } + }else{ + printk(KERN_ERR "%s: ERROR - Invalid Port Selected!\n", + card->wandev.name); + return -EINVAL; + } + + + /* Initialize protocol-specific fields */ + if(card->hw.type != SDLA_S514){ + + if (card->u.c.comm_port == WANOPT_PRI){ + card->mbox = (void *) card->hw.dpmbase; + }else{ + card->mbox = (void *) card->hw.dpmbase + + SEC_BASE_ADDR_MB_STRUCT - PRI_BASE_ADDR_MB_STRUCT; + } + }else{ + /* for a S514 adapter, set a pointer to the actual mailbox in the */ + /* allocated virtual memory area */ + if (card->u.c.comm_port == WANOPT_PRI){ + card->mbox = (void *) card->hw.dpmbase + PRI_BASE_ADDR_MB_STRUCT; + }else{ + card->mbox = (void *) card->hw.dpmbase + SEC_BASE_ADDR_MB_STRUCT; + } + } + + mb = mb1 = card->mbox; + + if (!card->configured){ + + /* The board will place an 'I' in the return code to indicate that it is + ready to accept commands. We expect this to be completed in less + than 1 second. */ + + timeout = jiffies; + while (mb->return_code != 'I') /* Wait 1s for board to initialize */ + if ((jiffies - timeout) > 1*HZ) break; + + if (mb->return_code != 'I') { + printk(KERN_INFO + "%s: Initialization not completed by adapter\n", + card->devname); + printk(KERN_INFO "Please contact Sangoma representative.\n"); + return -EIO; + } + } + + /* Read firmware version. Note that when adapter initializes, it + * clears the mailbox, so it may appear that the first command was + * executed successfully when in fact it was merely erased. To work + * around this, we execute the first command twice. + */ + + if (chdlc_read_version(card, u.str)) + return -EIO; + + printk(KERN_INFO "%s: Running Cisco HDLC firmware v%s\n", + card->devname, u.str); + + card->isr = &wpc_isr; + card->poll = NULL; + card->exec = NULL; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DUALPORT; + card->wandev.udp_port = conf->udp_port; + + card->wandev.new_if_cnt = 0; + + /* This is for the ports link state */ + card->u.c.state = WAN_DISCONNECTED; + + /* reset the number of times the 'update()' proc has been called */ + card->u.c.update_call_count = 0; + + card->wandev.ttl = conf->ttl; + card->wandev.interface = conf->interface; + + if ((card->u.c.comm_port == WANOPT_SEC && conf->interface == WANOPT_V35)&& + card->hw.type != SDLA_S514){ + printk(KERN_INFO "%s: ERROR - V35 Interface not supported on S508 %s port \n", + card->devname, PORT(card->u.c.comm_port)); + return -EIO; + } + + card->wandev.clocking = conf->clocking; + + port_num = card->u.c.comm_port; + + /* Setup Port Bps */ + + if(card->wandev.clocking) { + + if(port_num == WANOPT_PRI) { + /* For Primary Port 0 */ + max_permitted_baud = + (card->hw.type == SDLA_S514) ? + PRI_MAX_BAUD_RATE_S514 : + PRI_MAX_BAUD_RATE_S508; + } + else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + max_permitted_baud = + (card->hw.type == SDLA_S514) ? + SEC_MAX_BAUD_RATE_S514 : + SEC_MAX_BAUD_RATE_S508; + } + + if(conf->bps > max_permitted_baud) { + conf->bps = max_permitted_baud; + printk(KERN_INFO "%s: Baud too high!\n", + card->wandev.name); + printk(KERN_INFO "%s: Baud rate set to %lu bps\n", + card->wandev.name, max_permitted_baud); + } + + card->wandev.bps = conf->bps; + }else{ + card->wandev.bps = 0; + } + + /* Setup the Port MTU */ + if(port_num == WANOPT_PRI) { + /* For Primary Port 0 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + min(conf->mtu, PRI_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } else if(port_num == WANOPT_SEC) { + /* For Secondary Port 1 */ + card->wandev.mtu = + (conf->mtu >= MIN_LGTH_CHDLC_DATA_CFG) ? + min(conf->mtu, SEC_MAX_NO_DATA_BYTES_IN_FRAME) : + CHDLC_DFLT_DATA_LEN; + } + + /* Set up the interrupt status area */ + /* Read the CHDLC Configuration and obtain: + * Ptr to shared memory infor struct + * Use this pointer to calculate the value of card->u.c.flags ! + */ + mb1->buffer_length = 0; + mb1->command = READ_CHDLC_CONFIGURATION; + err = sdla_exec(mb1) ? mb1->return_code : CMD_TIMEOUT; + if(err != COMMAND_OK) { + clear_bit(1, (void*)&card->wandev.critical); + + if(card->hw.type != SDLA_S514) + enable_irq(card->hw.irq); + + chdlc_error(card, err, mb1); + return -EIO; + } + + if(card->hw.type == SDLA_S514){ + card->u.c.flags = (void *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> + ptr_shared_mem_info_struct)); + }else{ + card->u.c.flags = (void *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb1->data)-> + ptr_shared_mem_info_struct % SDLA_WINDOWSIZE)); + } + + return 0; +} + +/******* WAN Device Driver Entry Points *************************************/ + +/*============================================================================ + * Update device status & statistics + * This procedure is called when updating the PROC file system and returns + * various communications statistics. These statistics are accumulated from 3 + * different locations: + * 1) The 'if_stats' recorded for the device. + * 2) Communication error statistics on the adapter. + * 3) CHDLC operational statistics on the adapter. + * The board level statistics are read during a timer interrupt. Note that we + * read the error and operational statistics during consecitive timer ticks so + * as to minimize the time that we are inside the interrupt handler. + * + */ +static int update (wan_device_t* wandev) +{ + sdla_t* card = wandev->private; + struct net_device* dev = card->wandev.dev; + volatile chdlc_private_area_t* chdlc_priv_area = dev->priv; + SHARED_MEMORY_INFO_STRUCT *flags; + unsigned long timeout; + + /* sanity checks */ + if((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT; + + if(wandev->state == WAN_UNCONFIGURED) + return -ENODEV; + + /* more sanity checks */ + if(!card->u.c.flags) + return -ENODEV; + if(test_bit(1, (void*)&card->wandev.critical)) + return -EAGAIN; + + if(!dev->start) + return -ENODEV; + + flags = card->u.c.flags; + if(chdlc_priv_area->update_comms_stats){ + return -EAGAIN; + } + + /* we will need 2 timer interrupts to complete the */ + /* reading of the statistics */ + chdlc_priv_area->update_comms_stats = 2; + flags->interrupt_info_struct.interrupt_permission |= APP_INT_ON_TIMER; + chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UPDATE; + + /* wait a maximum of 1 second for the statistics to be updated */ + timeout = jiffies; + for(;;) { + if(chdlc_priv_area->update_comms_stats == 0) + break; + if ((jiffies - timeout) > (1 * HZ)){ + chdlc_priv_area->update_comms_stats = 0; + chdlc_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + } + + return 0; +} + + +/*============================================================================ + * Create new logical channel. + * This routine is called by the router when ROUTER_IFNEW IOCTL is being + * handled. + * o parse media- and hardware-specific configuration + * o make sure that a new channel can be created + * o allocate resources, if necessary + * o prepare network device structure for registaration. + * + * Return: 0 o.k. + * < 0 failure (channel will not be created) + */ +static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) +{ + sdla_t* card = wandev->private; + chdlc_private_area_t* chdlc_priv_area; + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", + card->devname); + return -EINVAL; + } + + /* allocate and initialize private data */ + chdlc_priv_area = kmalloc(sizeof(chdlc_private_area_t), GFP_KERNEL); + + if(chdlc_priv_area == NULL) + return -ENOMEM; + + memset(chdlc_priv_area, 0, sizeof(chdlc_private_area_t)); + + chdlc_priv_area->card = card; + + /* initialize data */ + strcpy(card->u.c.if_name, conf->name); + + if(card->wandev.new_if_cnt > 0) { + kfree(chdlc_priv_area); + return -EEXIST; + } + + card->wandev.new_if_cnt++; + + chdlc_priv_area->TracingEnabled = 0; + chdlc_priv_area->route_status = NO_ROUTE; + chdlc_priv_area->route_removed = 0; + + /* Setup protocol options */ + + card->u.c.protocol_options = 0; + + if (conf->ignore_dcd == WANOPT_YES){ + card->u.c.protocol_options |= IGNORE_DCD_FOR_LINK_STAT; + } + + if (conf->ignore_cts == WANOPT_YES){ + card->u.c.protocol_options |= IGNORE_CTS_FOR_LINK_STAT; + } + + if (conf->ignore_keepalive == WANOPT_YES) { + card->u.c.protocol_options |= IGNORE_KPALV_FOR_LINK_STAT; + card->u.c.kpalv_tx = MIN_Tx_KPALV_TIMER; + card->u.c.kpalv_rx = MIN_Rx_KPALV_TIMER; + card->u.c.kpalv_err = MIN_KPALV_ERR_TOL; + + } else { /* Do not ignore keepalives */ + + card->u.c.kpalv_tx = + (conf->keepalive_tx_tmr - MIN_Tx_KPALV_TIMER) >= 0 ? + min (conf->keepalive_tx_tmr, MAX_Tx_KPALV_TIMER) : + DEFAULT_Tx_KPALV_TIMER; + + card->u.c.kpalv_rx = + (conf->keepalive_rx_tmr - MIN_Rx_KPALV_TIMER) >= 0 ? + min (conf->keepalive_rx_tmr, MAX_Rx_KPALV_TIMER) : + DEFAULT_Rx_KPALV_TIMER; + + card->u.c.kpalv_err = + (conf->keepalive_err_margin - MIN_KPALV_ERR_TOL) >= 0 ? + min (conf->keepalive_err_margin, MAX_KPALV_ERR_TOL) : + DEFAULT_KPALV_ERR_TOL; + } + + + /* Setup slarp timer to control delay between slarps + */ + card->u.c.slarp_timer = + (conf->slarp_timer - MIN_SLARP_REQ_TIMER) >=0 ? + min (conf->slarp_timer, MAX_SLARP_REQ_TIMER) : + DEFAULT_SLARP_REQ_TIMER; + + + /* If HDLC_STRAMING is enabled then IGNORE DCD, CTS and KEEPALIVES + * are automatically ignored + */ + if (conf->hdlc_streaming == WANOPT_YES) { + printk(KERN_INFO "%s: Enabling HDLC STREAMING Mode\n", + wandev->name); + card->u.c.protocol_options = HDLC_STREAMING_MODE; + } + + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if( strcmp(conf->usedby, "WANPIPE") == 0) { + printk(KERN_INFO "%s: Running in WANPIPE mode !\n",wandev->name); + card->u.c.usedby = WANPIPE; + + } else if( strcmp(conf->usedby, "API") == 0){ + +#ifdef CHDLC_API + card->u.c.usedby = API; + printk(KERN_INFO "%s: Running in API mode !\n",wandev->name); +#else + printk(KERN_INFO "%s: API Mode is not supported!\n", + wandev->name); + printk(KERN_INFO "%s: Chdlc API patch can be obtained from Sangoma Tech.\n", + wandev->name); + kfree(chdlc_priv_area); + return -EINVAL; +#endif + } + + + /* Get Multicast Information */ + chdlc_priv_area->mc = conf->mc; + + /* prepare network device data space for registration */ + dev->name = card->u.c.if_name; + dev->init = &if_init; + dev->priv = chdlc_priv_area; + + return 0; +} + +/*============================================================================ + * Delete logical channel. + */ +static int del_if (wan_device_t* wandev, struct net_device* dev) +{ + +/* FIXME: This code generates kernel panic during + router stop!. Investigate futher. + (Error is dereferencing a NULL pointer) + + if(dev->priv){ + + kfree(dev->priv); + dev->priv = NULL; + + } +*/ + return 0; +} + + +/****** Network Device Interface ********************************************/ + +/*============================================================================ + * Initialize Linux network interface. + * + * This routine is called only once for each interface, during Linux network + * interface registration. Returning anything but zero will fail interface + * registration. + */ +static int if_init (struct net_device* dev) + { + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + wan_device_t* wandev = &card->wandev; +#ifndef LINUX_2_1 + int i; +#endif + + /* Initialize device driver entry points */ + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ + dev->flags |= IFF_POINTTOPOINT; + + /* Enable Mulitcasting if user selected */ + if (chdlc_priv_area->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + +#ifndef LINUX_2_1 + dev->family = AF_INET; +#endif + dev->type = ARPHRD_PPP; /* ARP hw type -- dummy value */ + dev->mtu = card->wandev.mtu; + dev->hard_header_len = CHDLC_HDR_LEN; + + /* Initialize hardware parameters */ + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length + * If too low packets will not be retransmitted + * by stack. + */ + dev->tx_queue_len = 100; + + /* Initialize socket buffers */ +#ifdef LINUX_2_1 + dev_init_buffers(dev); +#else + for (i = 0; i < DEV_NUMBUFFS; ++i) + skb_queue_head_init(&dev->buffs[i]); +#endif + + return 0; +} + +/*============================================================================ + * Open network interface. + * o enable communications and interrupts. + * o prevent module from unloading by incrementing use count + * + * Return 0 if O.k. or errno. + */ +static int if_open (struct net_device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + SHARED_MEMORY_INFO_STRUCT* flags = card->u.c.flags; + struct timeval tv; + int err = 0; + + /* Only one open per interface is allowed */ + + if(dev->start) + return -EBUSY; + + if(test_and_set_bit(1, (void*)&card->wandev.critical)) { + return -EAGAIN; + } + + /* Setup the Board for CHDLC */ + if (set_chdlc_config(card)) { + clear_bit(1, (void*)&card->wandev.critical); + return -EIO; + } + + if (!card->configured && !card->wandev.piggyback){ + /* Perform interrupt testing */ + err = intr_test(card, dev); + + if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { + printk(KERN_ERR "%s: Interrupt test failed (%i)\n", + card->devname, Intr_test_counter); + printk(KERN_ERR "%s: Please choose another interrupt\n", + card->devname); + clear_bit(1, (void*)&card->wandev.critical); + return -EIO; + } + + printk(KERN_INFO "%s: Interrupt test passed (%i)\n", + card->devname, Intr_test_counter); + card->configured = 1; + }else{ + printk(KERN_INFO "%s: Card configured, skip interrupt test\n", + card->devname); + } + + /* Initialize Rx/Tx buffer control fields */ + init_chdlc_tx_rx_buff(card, dev); + + /* Set interrupt mode and mask */ + if (chdlc_set_intr_mode(card, APP_INT_ON_RX_FRAME | + APP_INT_ON_GLOBAL_EXCEP_COND | + APP_INT_ON_TX_FRAME | + APP_INT_ON_CHDLC_EXCEP_COND | APP_INT_ON_TIMER)){ + + clear_bit(1, (void*)&card->wandev.critical); + return -EIO; + } + + + /* Mask the Transmit and Timer interrupt */ + flags->interrupt_info_struct.interrupt_permission &= + ~(APP_INT_ON_TX_FRAME | APP_INT_ON_TIMER); + + + /* Enable communications */ + if (chdlc_comm_enable(card)) { + clear_bit(1, (void*)&card->wandev.critical); + return -EIO; + } + + clear_bit(1, (void*)&card->wandev.critical); + + port_set_state(card, WAN_CONNECTING); + do_gettimeofday(&tv); + chdlc_priv_area->router_start_time = tv.tv_sec; + + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + dev->flags |= IFF_POINTTOPOINT; + wanpipe_open(card); + + return err; +} + +/*============================================================================ + * Close network interface. + * o if this is the last close, then disable communications and interrupts. + * o reset flags. + */ +static int if_close (struct net_device* dev) +{ + chdlc_private_area_t* chdlc_priv_area = dev->priv; + sdla_t* card = chdlc_priv_area->card; + + if(test_and_set_bit(1, (void*)&card->wandev.critical)) + return -EAGAIN; + + dev->start = 0; + wanpipe_close(card); + port_set_state(card, WAN_DISCONNECTED); + chdlc_set_intr_mode(card, 0); + chdlc_comm_disable(card); + + clear_bit(1, (void*)&card->wandev.critical); + + return 0; +} + +/*============================================================================ + * Build media header. + * + * The trick here is to put packet type (Ethertype) into 'protocol' field of + * the socket buffer, so that we don't forget it. If packet type is not + * supported, set skb->protocol to 0 and discard packet later. + * + * Return: media header length. + */ +static int if_header (struct sk_buff* skb, struct net_device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) +{ + skb->protocol = htons(type); + + return CHDLC_HDR_LEN; +} + +/*============================================================================ + * Re-build media header. + * + * Return: 1 physical address resolved. + * 0 physical address not resolved + */ +#ifdef LINUX_2_1 +static int if_rebuild_hdr (struct sk_buff *skb) +{ + return 1; +} +#else +static int if_rebuild_hdr (void* hdr, struct net_device* dev, unsigned long raddr, + struct sk_buff* skb) +{ + return 1; +} +#endif + +/*============================================================================ + * Send a packet on a network interface. + * o set tbusy flag (marks start of the transmission) to block a timer-based + * transmit from overlapping. + * o check link state. If link is not up, then drop the packet. + * o execute adapter send command. + * o free socket buffer + * + * Return: 0 complete (socket buffer must be freed) + * non-0 packet may be re-transmitted (tbusy must be set) + * + * Notes: + * 1. This routine is called either by the protocol stack or by the "net + * bottom half" (with interrupts enabled). + * 2. Setting tbusy flag will inhibit further transmit requests from the + * protocol stack and can be used for flow control with protocol layer. + */ +static int if_send (struct sk_buff* skb, struct net_device* dev) +{ + chdlc_private_area_t *chdlc_priv_area = dev->priv; + sdla_t *card = chdlc_priv_area->card; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + INTERRUPT_INFORMATION_STRUCT *chdlc_int = &flags->interrupt_info_struct; + int udp_type = 0; + unsigned long smp_flags; + + if(skb == NULL) { + /* If we get here, some higher layer thinks we've missed an + * tx-done interrupt. + */ + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + mark_bh(NET_BH); + return 0; + } + + if(dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + ++card->wandev.stats.collisions; + + if((jiffies - chdlc_priv_area->tick_counter) < (5 * HZ)) { + return 1; + } + + printk (KERN_INFO "%s: Transmit timeout !\n", + card->devname); + + /* unbusy the interface */ + dev->tbusy = 0; + } + + if(ntohs(skb->protocol) != 0x16) { + + /* check the udp packet type */ + udp_type = udp_pkt_type(skb, card); + if(udp_type == UDP_CPIPE_TYPE) { + if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, + chdlc_priv_area)) + chdlc_int->interrupt_permission |= + APP_INT_ON_TIMER; + return 0; + } + + /* check to see if the source IP address is a broadcast or */ + /* multicast IP address */ + if(chk_bcast_mcast_addr(card, dev, skb)) + return 0; + } + + /* Lock the 508 Card: SMP is supported */ + if(card->hw.type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if(test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "%s: Critical in if_send: %x\n", + card->wandev.name,card->wandev.critical); + ++card->wandev.stats.tx_dropped; +#ifdef LINUX_2_1 + dev_kfree_skb(skb); +#else + dev_kfree_skb(skb, FREE_WRITE); +#endif + if(card->hw.type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + return 0; + } + + if(card->u.c.state != WAN_CONNECTED) + ++card->wandev.stats.tx_dropped; + + else if(!skb->protocol) + ++card->wandev.stats.tx_errors; + + else { + void* data = skb->data; + unsigned len = skb->len; + unsigned char attr; + + /* If it's an API packet pull off the API + * header. Also check that the packet size + * is larger than the API header + */ + if (card->u.c.usedby == API){ + api_tx_hdr_t* api_tx_hdr; + + if (len <= sizeof(api_tx_hdr_t)){ +#ifdef LINUX_2_1 + dev_kfree_skb(skb); +#else + dev_kfree_skb(skb, FREE_WRITE); +#endif + ++card->wandev.stats.tx_dropped; + clear_bit(0, (void*)&card->wandev.critical); + if(card->hw.type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + return 0; + } + + api_tx_hdr = (api_tx_hdr_t *)data; + attr = api_tx_hdr->attr; + data += sizeof(api_tx_hdr_t); + len -= sizeof(api_tx_hdr_t); + } + + if(chdlc_send(card, data, len)) { + dev->tbusy = 1; + chdlc_priv_area->tick_counter = jiffies; + chdlc_int->interrupt_permission |= APP_INT_ON_TX_FRAME; + } + else { + ++card->wandev.stats.tx_packets; +#ifdef LINUX_2_1 + card->wandev.stats.tx_bytes += len; +#endif + } + } + + if (!dev->tbusy) { +#ifdef LINUX_2_1 + dev_kfree_skb(skb); +#else + dev_kfree_skb(skb, FREE_WRITE); +#endif + } + + clear_bit(0, (void*)&card->wandev.critical); + if(card->hw.type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + return dev->tbusy; +} + + +/*============================================================================ + * Check to see if the packet to be transmitted contains a broadcast or + * multicast source IP address. + */ + +static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, + struct sk_buff *skb) +{ + u32 src_ip_addr; + u32 broadcast_ip_addr = 0; +#ifdef LINUX_2_1 + struct in_device *in_dev; +#endif + /* read the IP source address from the outgoing packet */ + src_ip_addr = *(u32 *)(skb->data + 12); + + /* read the IP broadcast address for the device */ +#ifdef LINUX_2_1 + in_dev = dev->ip_ptr; + if(in_dev != NULL) { + struct in_ifaddr *ifa= in_dev->ifa_list; + if(ifa != NULL) + broadcast_ip_addr = ifa->ifa_broadcast; + else + return 0; + } +#else + broadcast_ip_addr = dev->pa_brdaddr; +#endif + + /* check if the IP Source Address is a Broadcast address */ + if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { + printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", + card->devname); +#ifdef LINUX_2_1 + dev_kfree_skb(skb); +#else + dev_kfree_skb(skb, FREE_WRITE); +#endif + ++card->wandev.stats.tx_dropped; + return 1; + } + + /* check if the IP Source Address is a Multicast address */ + if((ntohl(src_ip_addr) >= 0xE0000001) && + (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { + printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", + card->devname); +#ifdef LINUX_2_1 + dev_kfree_skb(skb); +#else + dev_kfree_skb(skb, FREE_WRITE); +#endif + ++card->wandev.stats.tx_dropped; + return 1; + } + + return 0; +} + + +/*============================================================================ + * Reply to UDP Management system. + * Return length of reply. + */ +static int reply_udp( unsigned char *data, unsigned int mbox_len ) +{ + + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + chdlc_udp_pkt_t *c_udp_pkt = (chdlc_udp_pkt_t *)data; + + /* Set length of packet */ + len = sizeof(ip_pkt_t)+ + sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + sizeof(trace_info_t)+ + mbox_len; + + /* fill in UDP reply */ + c_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; + + /* fill in UDP length */ + udp_length = sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + sizeof(trace_info_t)+ + mbox_len; + + /* put it on an even boundary */ + if ( udp_length & 0x0001 ) { + udp_length += 1; + len += 1; + even_bound = 1; + } + + temp = (udp_length<<8)|(udp_length>>8); + c_udp_pkt->udp_pkt.udp_length = temp; + + /* swap UDP ports */ + temp = c_udp_pkt->udp_pkt.udp_src_port; + c_udp_pkt->udp_pkt.udp_src_port = + c_udp_pkt->udp_pkt.udp_dst_port; + c_udp_pkt->udp_pkt.udp_dst_port = temp; + + /* add UDP pseudo header */ + temp = 0x1100; + *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *)(c_udp_pkt->data+mbox_len+even_bound+2)) = temp; + + + /* calculate UDP checksum */ + c_udp_pkt->udp_pkt.udp_checksum = 0; + c_udp_pkt->udp_pkt.udp_checksum = calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); + + /* fill in IP length */ + ip_length = len; + temp = (ip_length<<8)|(ip_length>>8); + c_udp_pkt->ip_pkt.total_length = temp; + + /* swap IP addresses */ + ip_temp = c_udp_pkt->ip_pkt.ip_src_address; + c_udp_pkt->ip_pkt.ip_src_address = c_udp_pkt->ip_pkt.ip_dst_address; + c_udp_pkt->ip_pkt.ip_dst_address = ip_temp; + + /* fill in IP checksum */ + c_udp_pkt->ip_pkt.hdr_checksum = 0; + c_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); + + return len; + +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i <len; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; + } + + while (sum >> 16 ) { + sum = (sum & 0xffffUL) + (sum >> 16); + } + + temp = (unsigned short)sum; + temp = ~temp; + + if( temp == 0 ) + temp = 0xffff; + + return temp; +} + + +/*============================================================================ + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. + */ +#ifdef LINUX_2_1 +static struct net_device_stats* if_stats (struct net_device* dev) +{ + sdla_t *my_card; + chdlc_private_area_t* chdlc_priv_area = dev->priv; + + my_card = chdlc_priv_area->card; + return &my_card->wandev.stats; +} +#else +static struct enet_statistics* if_stats (struct net_device* dev) +{ + sdla_t *my_card; + chdlc_private_area_t* chdlc_priv_area = dev->priv; + + my_card = chdlc_priv_area->card; + return &my_card->wandev.stats; +} +#endif + +/****** Cisco HDLC Firmware Interface Functions *******************************/ + +/*============================================================================ + * Read firmware code version. + * Put code version as ASCII string in str. + */ +static int chdlc_read_version (sdla_t* card, char* str) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int len; + char err; + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + } + else if (str) { /* is not null */ + len = mb->buffer_length; + memcpy(str, mb->data, len); + str[len] = '\0'; + } + return (err); +} + +/*----------------------------------------------------------------------------- + * Configure CHDLC firmware. + */ +static int chdlc_configure (sdla_t* card, void* data) +{ + int err; + CHDLC_MAILBOX_STRUCT *mailbox = card->mbox; + int data_length = sizeof(CHDLC_CONFIGURATION_STRUCT); + + mailbox->buffer_length = data_length; + memcpy(mailbox->data, data, data_length); + mailbox->command = SET_CHDLC_CONFIGURATION; + err = sdla_exec(mailbox) ? mailbox->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) chdlc_error (card, err, mailbox); + + return err; +} + + +/*============================================================================ + * Set interrupt mode -- HDLC Version. + */ + +static int chdlc_set_intr_mode (sdla_t* card, unsigned mode) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_INT_TRIGGERS_STRUCT* int_data = + (CHDLC_INT_TRIGGERS_STRUCT *)mb->data; + int err; + + int_data->CHDLC_interrupt_triggers = mode; + int_data->IRQ = card->hw.irq; + int_data->interrupt_timer = 1; + + mb->buffer_length = sizeof(CHDLC_INT_TRIGGERS_STRUCT); + mb->command = SET_CHDLC_INTERRUPT_TRIGGERS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error (card, err, mb); + return err; +} + + +/*============================================================================ + * Enable communications. + */ + +static int chdlc_comm_enable (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = ENABLE_CHDLC_COMMUNICATIONS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card, err, mb); + return err; +} + +/*============================================================================ + * Disable communications and Drop the Modem lines (DCD and RTS). + */ +static int chdlc_comm_disable (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = DISABLE_CHDLC_COMMUNICATIONS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + + mb->command = SET_MODEM_STATUS; + mb->buffer_length = 1; + mb->data[0] = 0; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + + return err; +} + +/*============================================================================ + * Read communication error statistics. + */ +static int chdlc_read_comm_err_stats (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = READ_COMMS_ERROR_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Read CHDLC operational statistics. + */ +static int chdlc_read_op_stats (sdla_t* card) +{ + int err; + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_OPERATIONAL_STATS; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) + chdlc_error(card,err,mb); + return err; +} + + +/*============================================================================ + * Update communications error and general packet statistics. + */ +static int update_comms_stats(sdla_t* card, + chdlc_private_area_t* chdlc_priv_area) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + COMMS_ERROR_STATS_STRUCT* err_stats; + CHDLC_OPERATIONAL_STATS_STRUCT *op_stats; + + /* on the first timer interrupt, read the comms error statistics */ + if(chdlc_priv_area->update_comms_stats == 2) { + if(chdlc_read_comm_err_stats(card)) + return 1; + err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; + card->wandev.stats.rx_over_errors = + err_stats->Rx_overrun_err_count; + card->wandev.stats.rx_crc_errors = + err_stats->CRC_err_count; + card->wandev.stats.rx_frame_errors = + err_stats->Rx_abort_count; + card->wandev.stats.rx_fifo_errors = + err_stats->Rx_dis_pri_bfrs_full_count; + card->wandev.stats.rx_missed_errors = + card->wandev.stats.rx_fifo_errors; + card->wandev.stats.tx_aborted_errors = + err_stats->sec_Tx_abort_count; + } + + /* on the second timer interrupt, read the operational statistics */ + else { + if(chdlc_read_op_stats(card)) + return 1; + op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; + card->wandev.stats.rx_length_errors = + (op_stats->Rx_Data_discard_short_count + + op_stats->Rx_Data_discard_long_count); + } + + return 0; +} + +/*============================================================================ + * Send packet. + * Return: 0 - o.k. + * 1 - no transmit buffers available + */ +static int chdlc_send (sdla_t* card, void* data, unsigned len) +{ + CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; + + if (txbuf->opp_flag) + return 1; + + sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); + + txbuf->frame_length = len; + txbuf->opp_flag = 1; /* start transmission */ + + /* Update transmit buffer control fields */ + card->u.c.txbuf = ++txbuf; + + if ((void*)txbuf > card->u.c.txbuf_last) + card->u.c.txbuf = card->u.c.txbuf_base; + + return 0; +} + +/****** Firmware Error Handler **********************************************/ + +/*============================================================================ + * Firmware error handler. + * This routine is called whenever firmware command returns non-zero + * return code. + * + * Return zero if previous command has to be cancelled. + */ +static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb) +{ + unsigned cmd = mb->command; + + switch (err) { + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + case S514_BOTH_PORTS_SAME_CLK_MODE: + if(cmd == SET_CHDLC_CONFIGURATION) { + printk(KERN_INFO + "%s: Configure both ports for the same clock source\n", + card->devname); + break; + } + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", + card->devname, cmd, err); + } + + return 0; +} + +/****** Interrupt Handlers **************************************************/ + +/*============================================================================ + * Cisco HDLC interrupt service routine. + */ +STATIC void wpc_isr (sdla_t* card) +{ + struct net_device* dev; + chdlc_private_area_t* chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT* flags = NULL; + int i, interrupt_serviced = 0; + sdla_t *my_card; + + + /* Check for which port the interrupt has been generated + * Since Secondary Port is piggybacking on the Primary + * the check must be done here. + */ + + flags = card->u.c.flags; + if (!flags->interrupt_info_struct.interrupt_type){ + /* Check for a second port (piggybacking) */ + if((my_card = card->next)){ + flags = my_card->u.c.flags; + if (flags->interrupt_info_struct.interrupt_type){ + card = my_card; + } + } + } + + dev = card->wandev.dev; + + card->in_isr = 1; + + /* if critical due to peripheral operations + * ie. update() or getstats() then reset the interrupt and + * wait for the board to retrigger. + */ + if(test_bit(1, (void*)&card->wandev.critical)) { + if(card->u.c.flags != NULL) { + flags = card->u.c.flags; + if(flags->interrupt_info_struct. + interrupt_type) { + flags->interrupt_info_struct. + interrupt_type = 0; + } + } + card->in_isr = 0; + return; + } + + + /* On a 508 Card, if critical due to if_send + * Major Error !!! + */ + if(card->hw.type != SDLA_S514) { + if(test_and_set_bit(0, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Critical while in ISR: %x\n", + card->devname, card->wandev.critical); + card->in_isr = 0; + return; + } + } + + /* FIXME: Take this check out later in the future */ + if(card->u.c.flags != NULL) { + + flags = card->u.c.flags; + + switch(flags->interrupt_info_struct.interrupt_type) { + + case RX_APP_INT_PEND: /* 0x01: receive interrupt */ + interrupt_serviced = 1; + rx_intr(card); + break; + + case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ + interrupt_serviced = 1; + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TX_FRAME; + + chdlc_priv_area = dev->priv; + dev->tbusy = 0; + mark_bh(NET_BH); + break; + + case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ + interrupt_serviced = 1; + ++ Intr_test_counter; + break; + + case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ + interrupt_serviced = 1; + process_chdlc_exception(card); + break; + + case GLOBAL_EXCEP_COND_APP_INT_PEND: + interrupt_serviced = 1; + process_global_exception(card); + break; + + case TIMER_APP_INT_PEND: + interrupt_serviced = 1; + timer_intr(card); + break; + + default: + break; + } + } + + if(!interrupt_serviced) { + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, + flags->interrupt_info_struct.interrupt_type); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codename[i]); + printk(KERN_INFO "\nCode version: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + } + + card->in_isr = 0; + flags->interrupt_info_struct.interrupt_type = 0; + if(card->hw.type != SDLA_S514){ + clear_bit(0, (void*)&card->wandev.critical); + } + +} + +/*============================================================================ + * Receive interrupt handler. + */ +static void rx_intr (sdla_t* card) +{ + struct net_device *dev; + chdlc_private_area_t *chdlc_priv_area; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; + struct sk_buff *skb; + unsigned len; + void *buf; + int i,udp_type; + + if (rxbuf->opp_flag != 0x01) { + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)rxbuf, rxbuf->opp_flag); + printk(KERN_INFO "Code name: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codename[i]); + printk(KERN_INFO "\nCode version: "); + for(i = 0; i < 4; i ++) + printk(KERN_INFO "%c", + flags->global_info_struct.codeversion[i]); + printk(KERN_INFO "\n"); + return; + } + + dev = card->wandev.dev; + chdlc_priv_area = dev->priv; + + if(dev && dev->start) { + + len = rxbuf->frame_length; + + /* Allocate socket buffer */ + skb = dev_alloc_skb(len); + + if (skb != NULL) { + /* Copy data to the socket buffer */ + unsigned addr = rxbuf->ptr_data_bfr; + + if((addr + len) > + card->u.c.rx_top + 1) { + unsigned tmp = + card->u.c.rx_top - addr + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.c.rx_base; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + + /* Decapsulate packet */ + skb->protocol = htons(ETH_P_IP); + + card->wandev.stats.rx_packets ++; +#ifdef LINUX_2_1 + card->wandev.stats.rx_bytes += skb->len; +#endif + udp_type = udp_pkt_type( skb, card ); + + if(udp_type == UDP_CPIPE_TYPE) { + if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, + card, skb, dev, chdlc_priv_area)) { + flags->interrupt_info_struct. + interrupt_permission |= + APP_INT_ON_TIMER; + } + + } else { + + if(card->u.c.usedby == API) { + api_rx_hdr_t* api_rx_hdr; + skb_push(skb, sizeof(api_rx_hdr_t)); + api_rx_hdr = + (api_rx_hdr_t*)&skb->data[0x00]; + api_rx_hdr->error_flag = + rxbuf->error_flag; + api_rx_hdr->time_stamp = + rxbuf->time_stamp; + skb->protocol = htons(0x16); + skb->pkt_type = PACKET_HOST; + } + +/* FIXME: we should check to see if the received packet is a multicast packet so that we can increment the multicast statistic + ++ chdlc_priv_area->if_stats.multicast; +*/ + /* Pass it up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + } + + } else { + printk(KERN_INFO + "%s: no socket buffers available!\n", + card->devname); + ++card->wandev.stats.rx_dropped; + } + } + + /* Release buffer element and calculate a pointer to the next one */ + rxbuf->opp_flag = 0x00; + card->u.c.rxmb = ++ rxbuf; + if((void*)rxbuf > card->u.c.rxbuf_last) + card->u.c.rxmb = card->u.c.rxbuf_base; +} + +/*============================================================================ + * Timer interrupt handler. + * The timer interrupt is used for two purposes: + * 1) Processing udp calls from 'cpipemon'. + * 2) Reading board-level statistics for updating the proc file system. + */ +void timer_intr(sdla_t *card) +{ + struct net_device* dev; + chdlc_private_area_t* chdlc_priv_area = NULL; + SHARED_MEMORY_INFO_STRUCT* flags = NULL; + + dev = card->wandev.dev; + chdlc_priv_area = dev->priv; + + /* process a udp call if pending */ + if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { + process_udp_mgmt_pkt(card, dev, + chdlc_priv_area); + chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; + } + + /* read the communications statistics if required */ + if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + update_comms_stats(card, chdlc_priv_area); + if(!(-- chdlc_priv_area->update_comms_stats)) { + chdlc_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + } + } + + /* only disable the timer interrupt if there are no udp or statistic */ + /* updates pending */ + if(!chdlc_priv_area->timer_int_enabled) { + flags = card->u.c.flags; + flags->interrupt_info_struct.interrupt_permission &= + ~APP_INT_ON_TIMER; + } +} + +/*------------------------------------------------------------------------------ + Miscellaneous Functions + - set_chdlc_config() used to set configuration options on the board +------------------------------------------------------------------------------*/ + +static int set_chdlc_config(sdla_t* card) +{ + + struct net_device * dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + CHDLC_CONFIGURATION_STRUCT cfg; + + memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); + + if(card->wandev.clocking) + cfg.baud_rate = card->wandev.bps; + + cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? + INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; + + cfg.modem_config_options = 0; + cfg.modem_status_timer = 100; + + cfg.CHDLC_protocol_options = card->u.c.protocol_options; + cfg.percent_data_buffer_for_Tx = 50; + cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | + CHDLC_RX_DATA_BYTE_COUNT_STAT); + cfg.max_CHDLC_data_field_length = card->wandev.mtu; + cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; + cfg.receive_keepalive_timer = card->u.c.kpalv_rx; + cfg.keepalive_error_tolerance = card->u.c.kpalv_err; + cfg.SLARP_request_timer = card->u.c.slarp_timer; + + if (cfg.SLARP_request_timer) { + cfg.IP_address = 0; + cfg.IP_netmask = 0; + } + else { +#ifdef LINUX_2_1 + struct in_device *in_dev = dev->ip_ptr; + + if(in_dev != NULL) { + struct in_ifaddr *ifa = in_dev->ifa_list; + + if (ifa != NULL ) { + cfg.IP_address = ntohl(ifa->ifa_local); + cfg.IP_netmask = ntohl(ifa->ifa_mask); + chdlc_priv_area->IP_address = + ntohl(ifa->ifa_local); + chdlc_priv_area->IP_netmask = + ntohl(ifa->ifa_mask); + } + } +#else + cfg.IP_address = ntohl(dev->pa_addr); + cfg.IP_netmask = ntohl(dev->pa_mask); + chdlc_priv_area->IP_address = ntohl(dev->pa_addr); + chdlc_priv_area->IP_netmask = ntohl(dev->pa_mask); +#endif + + /* FIXME: We must re-think this message in next release + if((cfg.IP_address & 0x000000FF) > 2) { + printk(KERN_WARNING "\n"); + printk(KERN_WARNING " WARNING:%s configured with an\n", + card->devname); + printk(KERN_WARNING " invalid local IP address.\n"); + printk(KERN_WARNING " Slarp pragmatics will fail.\n"); + printk(KERN_WARNING " IP address should be of the\n"); + printk(KERN_WARNING " format A.B.C.1 or A.B.C.2.\n"); + } + */ + } + + return chdlc_configure(card, &cfg); +} + + + +/*============================================================================ + * Process global exception condition + */ +static int process_global_exception(sdla_t *card) +{ + CHDLC_MAILBOX_STRUCT* mbox = card->mbox; + int err; + + mbox->buffer_length = 0; + mbox->command = READ_GLOBAL_EXCEPTION_CONDITION; + err = sdla_exec(mbox) ? mbox->return_code : CMD_TIMEOUT; + + if(err != CMD_TIMEOUT ){ + + switch(mbox->return_code) { + + case EXCEP_MODEM_STATUS_CHANGE: + + printk(KERN_INFO "%s: Modem status change\n", + card->devname); + + switch(mbox->data[0] & (DCD_HIGH | CTS_HIGH)) { + case (DCD_HIGH): + printk(KERN_INFO "%s: DCD high, CTS low\n",card->devname); + break; + case (CTS_HIGH): + printk(KERN_INFO "%s: DCD low, CTS high\n",card->devname); break; + case ((DCD_HIGH | CTS_HIGH)): + printk(KERN_INFO "%s: DCD high, CTS high\n",card->devname); + break; + default: + printk(KERN_INFO "%s: DCD low, CTS low\n",card->devname); + break; + } + break; + + case EXCEP_TRC_DISABLED: + printk(KERN_INFO "%s: Line trace disabled\n", + card->devname); + break; + + case EXCEP_IRQ_TIMEOUT: + printk(KERN_INFO "%s: IRQ timeout occurred\n", + card->devname); + break; + + default: + printk(KERN_INFO "%s: Global exception %x\n", + card->devname, mbox->return_code); + break; + } + } + return 0; +} + + +/*============================================================================ + * Process chdlc exception condition + */ +static int process_chdlc_exception(sdla_t *card) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int err; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_EXCEPTION_CONDITION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if(err != CMD_TIMEOUT) { + + switch (err) { + + case EXCEP_LINK_ACTIVE: + port_set_state(card, WAN_CONNECTED); + break; + + case EXCEP_LINK_INACTIVE_MODEM: + port_set_state(card, WAN_DISCONNECTED); + unconfigure_ip(card); + break; + + case EXCEP_LINK_INACTIVE_KPALV: + port_set_state(card, WAN_DISCONNECTED); + printk(KERN_INFO "%s: Keepalive timer expired.\n", + card->devname); + unconfigure_ip(card); + break; + + case EXCEP_IP_ADDRESS_DISCOVERED: + if (configure_ip(card)) + return -1; + break; + + case EXCEP_LOOPBACK_CONDITION: + printk(KERN_INFO "%s: Loopback Condition Detected.\n", + card->devname); + break; + + case NO_CHDLC_EXCEP_COND_TO_REPORT: + printk(KERN_INFO "%s: No exceptions reported.\n", + card->devname); + break; + } + + } + return 0; +} + + +/*============================================================================ + * Configure IP from SLARP negotiation + * This adds dynamic routes when SLARP has provided valid addresses + */ + +static int configure_ip (sdla_t* card) +{ + struct net_device *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area = dev->priv; + char err; + + /* set to discover */ + if(card->u.c.slarp_timer != 0x00) { + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_CONFIGURATION_STRUCT *cfg; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return -1; + } + + cfg = (CHDLC_CONFIGURATION_STRUCT *)mb->data; + chdlc_priv_area->IP_address = cfg->IP_address; + chdlc_priv_area->IP_netmask = cfg->IP_netmask; + } + + /* Set flag to add route */ + chdlc_priv_area->route_status = ADD_ROUTE; + + /* The idea here is to add the route in the poll routine. + This way, we aren't in interrupt context when adding routes */ + card->poll = process_route; + + return 0; +} + + +/*============================================================================ + * Un-Configure IP negotiated by SLARP + * This removes dynamic routes when the link becomes inactive. + */ + +static int unconfigure_ip (sdla_t* card) +{ + struct net_device *dev = card->wandev.dev; + chdlc_private_area_t *chdlc_priv_area= dev->priv; + + if (chdlc_priv_area->route_status == ROUTE_ADDED) { + chdlc_priv_area->route_status = REMOVE_ROUTE; + /* The idea here is to delete the route in + * the poll routine. + * This way, we aren't in interrupt context + * when adding routes + */ + card->poll = process_route; + } + return 0; +} + +/*============================================================================ + * Routine to add/remove routes + * Called like a polling routine when Routes are flagged to be added/removed. + */ + +static void process_route (sdla_t *card) +{ + struct net_device *dev = card->wandev.dev; + unsigned char port_num; + chdlc_private_area_t *chdlc_priv_area = NULL; + u32 local_IP_addr = 0; + u32 remote_IP_addr = 0; + u32 IP_netmask, IP_addr; + int err = 0; +#ifdef LINUX_2_1 + struct in_device *in_dev; + mm_segment_t fs; + struct ifreq if_info; + struct sockaddr_in *if_data1, *if_data2; +#else + unsigned long fs = 0; + struct rtentry route; +#endif + + chdlc_priv_area = dev->priv; + port_num = card->u.c.comm_port; + + if((chdlc_priv_area->route_status == ADD_ROUTE) && + ((chdlc_priv_area->IP_address & 0x000000FF) > 2)) { + printk(KERN_INFO "%s: Dynamic route failure.\n",card->devname); + if(card->u.c.slarp_timer) { + printk(KERN_INFO "%s: Bad IP address %s received\n", + card->devname, + in_ntoa(ntohl(chdlc_priv_area->IP_address))); + printk(KERN_INFO "%s: from remote station.\n", + card->devname); + }else{ + printk(KERN_INFO "%s: Bad IP address %s issued\n", + card->devname, + in_ntoa(ntohl(chdlc_priv_area->IP_address))); + printk(KERN_INFO "%s: to remote station. Local\n", + card->devname); + printk(KERN_INFO "%s: IP address must be A.B.C.1\n", + card->devname); + printk(KERN_INFO "%s: or A.B.C.2.\n",card->devname); + } + + /* remove the route due to the IP address error condition */ + chdlc_priv_area->route_status = REMOVE_ROUTE; + err = 1; + } + + /* If we are removing a route with bad IP addressing, then use the */ + /* locally configured IP addresses */ + if((chdlc_priv_area->route_status == REMOVE_ROUTE) && err) { + + /* do not remove a bad route that has already been removed */ + if(chdlc_priv_area->route_removed) { + card->poll = NULL; + return; + } + +#ifdef LINUX_2_1 + in_dev = dev->ip_ptr; + + if(in_dev != NULL) { + struct in_ifaddr *ifa = in_dev->ifa_list; + if (ifa != NULL ) { + local_IP_addr = ifa->ifa_local; + IP_netmask = ifa->ifa_mask; + } + } +#else + local_IP_addr = dev->pa_addr; + remote_IP_addr = dev->pa_dstaddr; + IP_netmask = dev->pa_mask; +#endif + }else{ + /* According to Cisco HDLC, if the point-to-point address is + A.B.C.1, then we are the opposite (A.B.C.2), and vice-versa. + */ + IP_netmask = ntohl(chdlc_priv_area->IP_netmask); + remote_IP_addr = ntohl(chdlc_priv_area->IP_address); + local_IP_addr = (remote_IP_addr & ntohl(0xFFFFFF00)) + + (~remote_IP_addr & ntohl(0x0003)); + + if(!card->u.c.slarp_timer) { + IP_addr = local_IP_addr; + local_IP_addr = remote_IP_addr; + remote_IP_addr = IP_addr; + } + } + + fs = get_fs(); /* Save file system */ + set_fs(get_ds()); /* Get user space block */ + +#ifdef LINUX_2_1 + /* Setup a structure for adding/removing routes */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + +#else + /* Setup a structure for adding/removing routes */ + dev->pa_mask = IP_netmask; + dev->pa_dstaddr = remote_IP_addr; + dev->pa_addr = local_IP_addr; + + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + ((struct sockaddr_in *)&(route.rt_dst))->sin_addr.s_addr = + dev->pa_dstaddr; + ((struct sockaddr_in *)&(route.rt_dst))->sin_family = AF_INET; + ((struct sockaddr_in *)&(route.rt_genmask))->sin_addr.s_addr = + 0xFFFFFFFF; + ((struct sockaddr_in *)&(route.rt_genmask))->sin_family = + AF_INET; +#endif + + switch (chdlc_priv_area->route_status) { + + case ADD_ROUTE: + + if(!card->u.c.slarp_timer) { +#ifdef LINUX_2_1 + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = remote_IP_addr; + if_data2->sin_family = AF_INET; + err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); +#else + err = ip_rt_new(&route); +#endif + } else { +#ifdef LINUX_2_1 + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = local_IP_addr; + if_data1->sin_family = AF_INET; + if(!(err = devinet_ioctl(SIOCSIFADDR, &if_info))){ + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = remote_IP_addr; + if_data2->sin_family = AF_INET; + err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); + } +#else + err = ip_rt_new(&route); +#endif + } + + if(err) { + printk(KERN_INFO "%s: Add route %s failed (%d)\n", + card->devname, in_ntoa(remote_IP_addr), err); + } else { + ((chdlc_private_area_t *)dev->priv)->route_status = ROUTE_ADDED; + printk(KERN_INFO "%s: Dynamic route added.\n", + card->devname); + printk(KERN_INFO "%s: Local IP addr : %s\n", + card->devname, in_ntoa(local_IP_addr)); + printk(KERN_INFO "%s: Remote IP addr: %s\n", + card->devname, in_ntoa(remote_IP_addr)); + chdlc_priv_area->route_removed = 0; + } + break; + + + case REMOVE_ROUTE: + +#ifdef LINUX_2_1 + /* Change the local ip address of the interface to 0. + * This will also delete the destination route. + */ + if(!card->u.c.slarp_timer) { + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = 0; + if_data2->sin_family = AF_INET; + err = devinet_ioctl(SIOCSIFDSTADDR, &if_info); + } else { + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = 0; + if_data1->sin_family = AF_INET; + err = devinet_ioctl(SIOCSIFADDR,&if_info); + + } +#else + /* set the point-to-point IP address to 0.0.0.0 */ + dev->pa_dstaddr = 0; + err = ip_rt_kill(&route); +#endif + if(err) { + printk(KERN_INFO + "%s: Remove route %s failed, (err %d)\n", + card->devname, in_ntoa(remote_IP_addr), + err); + } else { + ((chdlc_private_area_t *)dev->priv)->route_status = + NO_ROUTE; + printk(KERN_INFO "%s: Dynamic route removed: %s\n", + card->devname, in_ntoa(local_IP_addr)); + chdlc_priv_area->route_removed = 1; + } + break; + } + + set_fs(fs); /* Restore file system */ + + /* Once we've processed the route, stop polling */ + card->poll = NULL; + +} + + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, struct net_device* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + int udp_pkt_stored = 0; + + if(!chdlc_priv_area->udp_pkt_lgth && + (skb->len <= MAX_LGTH_UDP_MGNT_PKT)) { + chdlc_priv_area->udp_pkt_lgth = skb->len; + chdlc_priv_area->udp_pkt_src = udp_pkt_src; + memcpy(chdlc_priv_area->udp_pkt_data, skb->data, skb->len); + chdlc_priv_area->timer_int_enabled = TMR_INT_ENABLED_UDP; + udp_pkt_stored = 1; + } + +#ifdef LINUX_2_1 + dev_kfree_skb(skb); +#else + if(udp_pkt_src == UDP_PKT_FRM_STACK) + dev_kfree_skb(skb, FREE_WRITE); + else + dev_kfree_skb(skb, FREE_READ); +#endif + + return(udp_pkt_stored); +} + + +/*============================================================================= + * Process UDP management packet. + */ + +static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev, + chdlc_private_area_t* chdlc_priv_area ) +{ + unsigned char *buf; + unsigned int frames, len; + struct sk_buff *new_skb; + unsigned short buffer_length, real_len; + unsigned long data_ptr; + unsigned data_length; + int udp_mgmt_req_valid = 1; + CHDLC_MAILBOX_STRUCT *mb = card->mbox; + SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; + chdlc_udp_pkt_t *chdlc_udp_pkt; + struct timeval tv; + int err; + char ut_char; + + chdlc_udp_pkt = (chdlc_udp_pkt_t *) chdlc_priv_area->udp_pkt_data; + + switch(chdlc_udp_pkt->cblock.command) { + + case FT1_MONITOR_STATUS_CTRL: + case CPIPE_ENABLE_TRACING: + case CPIPE_DISABLE_TRACING: + case CPIPE_GET_TRACE_INFO: + case SET_FT1_MODE: + if(chdlc_priv_area->udp_pkt_src == + UDP_PKT_FRM_NETWORK) { + udp_mgmt_req_valid = 0; + } + break; + + default: + break; + } + + if(!udp_mgmt_req_valid) { + + /* set length to 0 */ + chdlc_udp_pkt->cblock.buffer_length = 0; + + /* set return code */ + chdlc_udp_pkt->cblock.return_code = 0xCD; + + } else { + unsigned long trace_status_cfg_addr = 0; + TRACE_STATUS_EL_CFG_STRUCT trace_cfg_struct; + TRACE_STATUS_ELEMENT_STRUCT trace_element_struct; + + switch(chdlc_udp_pkt->cblock.command) { + + case CPIPE_ENABLE_TRACING: + if (!chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_ACTIVE; + /* Trace delay mode is not used because it slows + down transfer and results in a standoff situation + when there is a lot of data */ + + /* Configure the Trace based on user inputs */ + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)->trace_config |= + chdlc_udp_pkt->data[0]; + + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_deactivation_timer = 4000; + + + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + card->TracingEnabled = 0; + chdlc_udp_pkt->cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + /* Get the base address of the trace element list */ + mb->buffer_length = 0; + mb->command = READ_TRACE_CONFIGURATION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if (err != COMMAND_OK) { + chdlc_error(card,err,mb); + chdlc_priv_area->TracingEnabled = 0; + chdlc_udp_pkt->cblock.return_code = err; + mb->buffer_length = 0; + break; + } + + trace_status_cfg_addr =((LINE_TRACE_CONFIG_STRUCT *) + mb->data) -> ptr_trace_stat_el_cfg_struct; + + sdla_peek(&card->hw, trace_status_cfg_addr, + &trace_cfg_struct, sizeof(trace_cfg_struct)); + + chdlc_priv_area->start_trace_addr = trace_cfg_struct. + base_addr_trace_status_elements; + + chdlc_priv_area->number_trace_elements = + trace_cfg_struct.number_trace_status_elements; + + chdlc_priv_area->end_trace_addr = (unsigned long) + ((TRACE_STATUS_ELEMENT_STRUCT *) + chdlc_priv_area->start_trace_addr + + (chdlc_priv_area->number_trace_elements - 1)); + + chdlc_priv_area->base_addr_trace_buffer = + trace_cfg_struct.base_addr_trace_buffer; + + chdlc_priv_area->end_addr_trace_buffer = + trace_cfg_struct.end_addr_trace_buffer; + + chdlc_priv_area->curr_trace_addr = + trace_cfg_struct.next_trace_element_to_use; + + chdlc_priv_area->available_buffer_space = 2000 - + sizeof(ip_pkt_t) - + sizeof(udp_pkt_t) - + sizeof(wp_mgmt_t) - + sizeof(cblock_t) - + sizeof(trace_info_t); + } + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + chdlc_priv_area->TracingEnabled = 1; + break; + + + case CPIPE_DISABLE_TRACING: + if (chdlc_priv_area->TracingEnabled) { + + /* OPERATE_DATALINE_MONITOR */ + mb->buffer_length = sizeof(LINE_TRACE_CONFIG_STRUCT); + mb->command = SET_TRACE_CONFIGURATION; + ((LINE_TRACE_CONFIG_STRUCT *)mb->data)-> + trace_config = TRACE_INACTIVE; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + } + + chdlc_priv_area->TracingEnabled = 0; + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + mb->buffer_length = 0; + break; + + + case CPIPE_GET_TRACE_INFO: + + if (!chdlc_priv_area->TracingEnabled) { + chdlc_udp_pkt->cblock.return_code = 1; + mb->buffer_length = 0; + break; + } + + chdlc_udp_pkt->trace_info.ismoredata = 0x00; + buffer_length = 0; /* offset of packet already occupied */ + + for (frames=0; frames < chdlc_priv_area->number_trace_elements; frames++){ + + trace_pkt_t *trace_pkt = (trace_pkt_t *) + &chdlc_udp_pkt->data[buffer_length]; + + sdla_peek(&card->hw, chdlc_priv_area->curr_trace_addr, + (unsigned char *)&trace_element_struct, + sizeof(TRACE_STATUS_ELEMENT_STRUCT)); + + if (trace_element_struct.opp_flag == 0x00) { + break; + } + + /* get pointer to real data */ + data_ptr = trace_element_struct.ptr_data_bfr; + + /* See if there is actual data on the trace buffer */ + if (data_ptr){ + data_length = trace_element_struct.trace_length; + }else{ + data_length = 0; + chdlc_udp_pkt->trace_info.ismoredata = 0x01; + } + + if( (chdlc_priv_area->available_buffer_space - buffer_length) + < ( sizeof(trace_pkt_t) + data_length) ) { + + /* indicate there are more frames on board & exit */ + chdlc_udp_pkt->trace_info.ismoredata = 0x01; + break; + } + + trace_pkt->status = trace_element_struct.trace_type; + + trace_pkt->time_stamp = + trace_element_struct.trace_time_stamp; + + trace_pkt->real_length = + trace_element_struct.trace_length; + + /* see if we can fit the frame into the user buffer */ + real_len = trace_pkt->real_length; + + if (data_ptr == 0) { + trace_pkt->data_avail = 0x00; + } else { + unsigned tmp = 0; + + /* get the data from circular buffer + must check for end of buffer */ + trace_pkt->data_avail = 0x01; + + if ((data_ptr + real_len) > + chdlc_priv_area->end_addr_trace_buffer + 1){ + + tmp = chdlc_priv_area->end_addr_trace_buffer - data_ptr + 1; + sdla_peek(&card->hw, data_ptr, + trace_pkt->data,tmp); + data_ptr = chdlc_priv_area->base_addr_trace_buffer; + } + + sdla_peek(&card->hw, data_ptr, + &trace_pkt->data[tmp], real_len - tmp); + } + + /* zero the opp flag to show we got the frame */ + ut_char = 0x00; + sdla_poke(&card->hw, chdlc_priv_area->curr_trace_addr, &ut_char, 1); + + /* now move onto the next frame */ + chdlc_priv_area->curr_trace_addr += sizeof(TRACE_STATUS_ELEMENT_STRUCT); + + /* check if we went over the last address */ + if ( chdlc_priv_area->curr_trace_addr > chdlc_priv_area->end_trace_addr ) { + chdlc_priv_area->curr_trace_addr = chdlc_priv_area->start_trace_addr; + } + + if(trace_pkt->data_avail == 0x01) { + buffer_length += real_len - 1; + } + + /* for the header */ + buffer_length += sizeof(trace_pkt_t); + + } /* For Loop */ + + if (frames == chdlc_priv_area->number_trace_elements){ + chdlc_udp_pkt->trace_info.ismoredata = 0x01; + } + chdlc_udp_pkt->trace_info.num_frames = frames; + + mb->buffer_length = buffer_length; + chdlc_udp_pkt->cblock.buffer_length = buffer_length; + + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + + break; + + + case CPIPE_FT1_READ_STATUS: + ((unsigned char *)chdlc_udp_pkt->data )[0] = + flags->FT1_info_struct.parallel_port_A_input; + + ((unsigned char *)chdlc_udp_pkt->data )[1] = + flags->FT1_info_struct.parallel_port_B_input; + + chdlc_udp_pkt->cblock.return_code = COMMAND_OK; + mb->buffer_length = 2; + break; + + case CPIPE_ROUTER_UP_TIME: + do_gettimeofday( &tv ); + chdlc_priv_area->router_up_time = tv.tv_sec - + chdlc_priv_area->router_start_time; + *(unsigned long *)&chdlc_udp_pkt->data = + chdlc_priv_area->router_up_time; + mb->buffer_length = sizeof(unsigned long); + break; + + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ + if ((chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_STATUS) || + (chdlc_udp_pkt->data[0] & ENABLE_READ_FT1_OP_STATS)) { + + if( rCount++ != 0 ) { + chdlc_udp_pkt->cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( chdlc_udp_pkt->data[0] == 0) { + + if( --rCount != 0) { + chdlc_udp_pkt->cblock. + return_code = COMMAND_OK; + mb->buffer_length = 1; + break; + } + } + + default: + /* it's a board command */ + mb->command = chdlc_udp_pkt->cblock.command; + mb->buffer_length = chdlc_udp_pkt->cblock.buffer_length; + if (mb->buffer_length) { + memcpy(&mb->data, (unsigned char *) chdlc_udp_pkt-> + data, mb->buffer_length); + } + /* run the command on the board */ + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != COMMAND_OK) { + break; + } + + /* copy the result back to our buffer */ + memcpy(&chdlc_udp_pkt->cblock, mb, sizeof(cblock_t)); + + if (mb->buffer_length) { + memcpy(&chdlc_udp_pkt->data, &mb->data, + mb->buffer_length); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + chdlc_udp_pkt->ip_pkt.ttl = card->wandev.ttl; + + len = reply_udp(chdlc_priv_area->udp_pkt_data, mb->buffer_length); + + if(chdlc_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + if(!chdlc_send(card, chdlc_priv_area->udp_pkt_data, len)) { + ++ card->wandev.stats.tx_packets; +#ifdef LINUX_2_1 + card->wandev.stats.tx_bytes += len; +#endif + } + } else { + + /* Pass it up the stack + Allocate socket buffer */ + if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ + + buf = skb_put(new_skb, len); + memcpy(buf, chdlc_priv_area->udp_pkt_data, len); + + /* Decapsulate pkt and pass it up the protocol stack */ + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; + + netif_rx(new_skb); + } else { + + printk(KERN_INFO "%s: no socket buffers available!\n", + card->devname); + } + } + + chdlc_priv_area->udp_pkt_lgth = 0; + + return 0; +} + +/*============================================================================ + * Initialize Receive and Transmit Buffers. + */ + +static void init_chdlc_tx_rx_buff( sdla_t* card, struct net_device *dev ) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config; + CHDLC_RX_STATUS_EL_CFG_STRUCT *rx_config; + char err; + + mb->buffer_length = 0; + mb->command = READ_CHDLC_CONFIGURATION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + + if(err != COMMAND_OK) { + chdlc_error(card,err,mb); + return; + } + + if(card->hw.type == SDLA_S514) { + tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct)); + rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct)); + + /* Setup Head and Tails for buffers */ + card->u.c.txbuf_base = (void *)(card->hw.dpmbase + + tx_config->base_addr_Tx_status_elements); + card->u.c.txbuf_last = + (CHDLC_DATA_TX_STATUS_EL_STRUCT *) + card->u.c.txbuf_base + + (tx_config->number_Tx_status_elements - 1); + + card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + + rx_config->base_addr_Rx_status_elements); + card->u.c.rxbuf_last = + (CHDLC_DATA_RX_STATUS_EL_STRUCT *) + card->u.c.rxbuf_base + + (rx_config->number_Rx_status_elements - 1); + + /* Set up next pointer to be used */ + card->u.c.txbuf = (void *)(card->hw.dpmbase + + tx_config->next_Tx_status_element_to_use); + card->u.c.rxmb = (void *)(card->hw.dpmbase + + rx_config->next_Rx_status_element_to_use); + } + else { + tx_config = (CHDLC_TX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Tx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + rx_config = (CHDLC_RX_STATUS_EL_CFG_STRUCT *)(card->hw.dpmbase + + (((CHDLC_CONFIGURATION_STRUCT *)mb->data)-> + ptr_CHDLC_Rx_stat_el_cfg_struct % SDLA_WINDOWSIZE)); + + /* Setup Head and Tails for buffers */ + card->u.c.txbuf_base = (void *)(card->hw.dpmbase + + (tx_config->base_addr_Tx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.txbuf_last = + (CHDLC_DATA_TX_STATUS_EL_STRUCT *)card->u.c.txbuf_base + + (tx_config->number_Tx_status_elements - 1); + card->u.c.rxbuf_base = (void *)(card->hw.dpmbase + + (rx_config->base_addr_Rx_status_elements % SDLA_WINDOWSIZE)); + card->u.c.rxbuf_last = + (CHDLC_DATA_RX_STATUS_EL_STRUCT *)card->u.c.rxbuf_base + + (rx_config->number_Rx_status_elements - 1); + + /* Set up next pointer to be used */ + card->u.c.txbuf = (void *)(card->hw.dpmbase + + (tx_config->next_Tx_status_element_to_use % SDLA_WINDOWSIZE)); + card->u.c.rxmb = (void *)(card->hw.dpmbase + + (rx_config->next_Rx_status_element_to_use % SDLA_WINDOWSIZE)); + } + + /* Setup Actual Buffer Start and end addresses */ + card->u.c.rx_base = rx_config->base_addr_Rx_buffer; + card->u.c.rx_top = rx_config->end_addr_Rx_buffer; + +} + +/*============================================================================= + * Perform Interrupt Test by running READ_CHDLC_CODE_VERSION command MAX_INTR + * _TEST_COUNTER times. + */ +static int intr_test( sdla_t* card, struct net_device *dev ) +{ + CHDLC_MAILBOX_STRUCT* mb = card->mbox; + int err,i; + + Intr_test_counter = 0; + + /* The critical flag is unset because during intialization (if_open) + * we want the interrupts to be enabled so that when the wpc_isr is + * called it does not exit due to critical flag set. + */ + + clear_bit(1, (void*)&card->wandev.critical); + err = chdlc_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE); + + if (err == CMD_OK) { + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { + mb->buffer_length = 0; + mb->command = READ_CHDLC_CODE_VERSION; + err = sdla_exec(mb) ? mb->return_code : CMD_TIMEOUT; + if (err != CMD_OK) + chdlc_error(card, err, mb); + } + } + else { + return err; + } + + err = chdlc_set_intr_mode(card, 0); + set_bit(1, (void*)&card->wandev.critical); + + + if (err != CMD_OK) + return err; + + return 0; +} + +/*============================================================================== + * Determine what type of UDP call it is. CPIPEAB ? + */ +static int udp_pkt_type(struct sk_buff *skb, sdla_t* card) +{ + chdlc_udp_pkt_t *chdlc_udp_pkt = (chdlc_udp_pkt_t *)skb->data; + + if (!strncmp(chdlc_udp_pkt->wp_mgmt.signature,UDPMGMT_SIGNATURE,8) && + (chdlc_udp_pkt->udp_pkt.udp_dst_port == ntohs(card->wandev.udp_port)) && + (chdlc_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && + (chdlc_udp_pkt->wp_mgmt.request_reply == UDPMGMT_REQUEST)) { + return UDP_CPIPE_TYPE; + } + else return UDP_INVALID_TYPE; +} + +/*============================================================================ + * Set PORT state. + */ +static void port_set_state (sdla_t *card, int state) +{ + if (card->u.c.state != state) + { + switch (state) + { + case WAN_CONNECTED: + printk (KERN_INFO "%s: Link connected!\n", + card->devname); + break; + + case WAN_CONNECTING: + printk (KERN_INFO "%s: Link connecting...\n", + card->devname); + break; + + case WAN_DISCONNECTED: + printk (KERN_INFO "%s: Link disconnected!\n", + card->devname); + break; + } + + card->wandev.state = card->u.c.state = state; + } +} + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ +#ifdef __SMP__ + spin_lock_irqsave(&card->lock, *smp_flags); + if (card->next){ + spin_lock(&card->next->lock); + } +#else + disable_irq(card->hw.irq); +#endif +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ +#ifdef __SMP__ + if (card->next){ + spin_unlock(&card->next->lock); + } + spin_unlock_irqrestore(&card->lock, *smp_flags); +#else + enable_irq(card->hw.irq); +#endif +} + +/****** End ****************************************************************/ diff --git a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c index 6b2201a81..0c7f7e8f0 100644 --- a/drivers/net/wan/sdla_fr.c +++ b/drivers/net/wan/sdla_fr.c @@ -1,16 +1,38 @@ /***************************************************************************** * sdla_fr.c WANPIPE(tm) Multiprotocol WAN Link Driver. Frame relay module. * -* Author(s): Gene Kozin -* Jaspreet Singh <jaspreet@sangoma.com> +* Author(s): Nenad Corbic <ncorbic@sangoma.com> +* Gideon Hack * -* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. * * 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 the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Nov 08, 1999 Nenad Corbic o Combined all debug UDP calls into one function +* o Removed the ARP support. This has to be done +* in the next version. +* o Only a Node can implement NO signalling. +* Initialize DLCI during if_open() if NO +* signalling. +* o Took out IPX support, implement in next +* version +* Sep 29, 1999 Nenad Corbic o Added SMP support and changed the update +* function to use timer interrupt. +* o Fixed the CIR bug: Set the value of BC +* to CIR when the CIR is enabled. +* o Updated comments, statistics and tracing. +* Jun 02, 1999 Gideon Hack o Updated for S514 support. +* Sep 18, 1998 Jaspreet Singh o Updated for 2.2.X kernels. +* Jul 31, 1998 Jaspreet Singh o Removed wpf_poll routine. The channel/DLCI +* status is received through an event interrupt. +* Jul 08, 1998 David Fong o Added inverse ARP support. +* Mar 26, 1997 Jaspreet Singh o Returning return codes for failed UDP cmds. +* Jan 28, 1997 Jaspreet Singh o Improved handling of inactive DLCIs. +* Dec 30, 1997 Jaspreet Singh o Replaced dev_tint() with mark_bh(NET_BH) +* Dec 16, 1997 Jaspreet Singh o Implemented Multiple IPX support. * Nov 26, 1997 Jaspreet Singh o Improved load sharing with multiple boards * o Added Cli() to protect enabling of interrupts * while polling is called. @@ -42,7 +64,8 @@ * o Added ability to discard multicast and * broadcast source addressed packets * Jun 27, 1997 Jaspreet Singh o Added FT1 monitor capabilities -* New case (0x44) statement in if_send routine * Added a global variable rCount to keep track +* New case (0x44) statement in if_send routine +* Added a global variable rCount to keep track * of FT1 status enabled on the board. * May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem * With multiple boards a problem was seen where @@ -50,13 +73,15 @@ * packet after running for a while. The code * got into a stage where the interrupts were * disabled and dev->tbusy was set to 1. -* This caused the If_send() routine to get into* the if clause for it(0,dev->tbusy) +* This caused the If_send() routine to get into +* the if clause for it(0,dev->tbusy) * forever. * The code got into this stage due to an -* interrupt occurring within the if clause for +* interrupt occuring within the if clause for * set_bit(0,dev->tbusy). Since an interrupt * disables furhter transmit interrupt and -* makes dev->tbusy = 0, this effect was undone * by making dev->tbusy = 1 in the if clause. +* makes dev->tbusy = 0, this effect was undone +* by making dev->tbusy = 1 in the if clause. * The Fix checks to see if Transmit interrupts * are disabled then do not make dev->tbusy = 1 * Introduced a global variable: int_occur and @@ -83,6 +108,7 @@ * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ +#include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ @@ -93,140 +119,133 @@ #include <linux/if_arp.h> /* ARPHRD_* defines */ #include <asm/byteorder.h> /* htons(), etc. */ #include <asm/io.h> /* for inb(), outb(), etc. */ -#include <linux/time.h> /* for do_gettimeofday */ -#define _GNUC_ -#include <linux/sdla_fr.h> /* frame relay firmware API definitions */ +#include <linux/time.h> /* for do_gettimeofday */ +#include <linux/in.h> /* sockaddr_in */ +#include <linux/inet.h> /* in_ntoa(), etc... */ #include <asm/uaccess.h> +#include <linux/inetdevice.h> +#include <linux/ip.h> +#include <net/route.h> /* Dynamic Route Creation */ +#include <linux/if.h> +#include <linux/sdla_fr.h> /* frame relay firmware API definitions */ +#if LINUX_VERSION_CODE < 0x020125 +#define test_and_set_bit set_bit +#endif + /****** Defines & Macros ****************************************************/ -#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -#define FR_HEADER_LEN 8 /* max encapsulation header size */ -#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ +#define MAX_CMD_RETRY 10 /* max number of firmware retries */ -/* Q.922 frame types */ +#define FR_HEADER_LEN 8 /* max encapsulation header size */ +#define FR_CHANNEL_MTU 1500 /* unfragmented logical channel MTU */ -#define Q922_UI 0x03 /* Unnumbered Info frame */ -#define Q922_XID 0xAF /* ??? */ +/* Q.922 frame types */ +#define Q922_UI 0x03 /* Unnumbered Info frame */ +#define Q922_XID 0xAF /* DLCI configured or not */ - #define DLCI_NOT_CONFIGURED 0x00 #define DLCI_CONFIG_PENDING 0x01 #define DLCI_CONFIGURED 0x02 /* CIR enabled or not */ - #define CIR_ENABLED 0x00 #define CIR_DISABLED 0x01 -/* Interrupt mode for DLCI = 0 */ - -#define BUFFER_INTR_MODE 0x00 -#define DLCI_LIST_INTR_MODE 0x01 - -/* Transmit Interrupt Status */ - -#define DISABLED 0x00 -#define WAITING_TO_BE_ENABLED 0x01 +#define WANPIPE 0x00 +#define API 0x01 +#define FRAME_RELAY_API 1 /* For handle_IPXWAN() */ - #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) - + /****** Data Structures *****************************************************/ /* This is an extention of the 'struct net_device' we create for each network * interface to keep the rest of channel-specific data. */ -typedef struct fr_channel { - char name[WAN_IFNAME_SZ + 1]; /* interface name, ASCIIZ */ - unsigned dlci_configured; /* check whether configured or not */ - unsigned cir_status; /* check whether CIR enabled or not */ - unsigned dlci; /* logical channel number */ - unsigned cir; /* committed information rate */ - unsigned bc; /* committed burst size */ - unsigned be; /* excess burst size */ - unsigned mc; /* multicast support on or off */ - unsigned tx_int_status; /* Transmit Interrupt Status */ +typedef struct fr_channel +{ + char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */ + unsigned dlci_configured ; /* check whether configured or not */ + unsigned cir_status; /* check whether CIR enabled or not */ + unsigned dlci; /* logical channel number */ + unsigned cir; /* committed information rate */ + unsigned bc; /* committed burst size */ + unsigned be; /* excess burst size */ + unsigned mc; /* multicast support on or off */ + unsigned tx_int_status; /* Transmit Interrupt Status */ unsigned short pkt_length; /* Packet Length */ - unsigned long router_start_time; /* Router start time in seconds */ + unsigned long router_start_time;/* Router start time in seconds */ unsigned long tick_counter; /* counter for transmit time out */ char dev_pending_devtint; /* interface pending dev_tint() */ - char state; /* channel state */ - void *dlci_int_interface; /* pointer to the DLCI Interface */ - unsigned long IB_addr; /* physical address of Interface Byte */ + char state; /* channel state */ + void *dlci_int_interface; /* pointer to the DLCI Interface */ + unsigned long IB_addr; /* physical address of Interface Byte */ unsigned long state_tick; /* time of the last state change */ - sdla_t *card; /* -> owner */ - struct net_device_stats ifstats; /* interface statistics */ - unsigned long if_send_entry; - unsigned long if_send_skb_null; - unsigned long if_send_broadcast; - unsigned long if_send_multicast; - unsigned long if_send_critical_ISR; - unsigned long if_send_critical_non_ISR; - unsigned long if_send_busy; - unsigned long if_send_busy_timeout; - unsigned long if_send_FPIPE_request; - unsigned long if_send_DRVSTATS_request; - unsigned long if_send_wan_disconnected; - unsigned long if_send_dlci_disconnected; - unsigned long if_send_no_bfrs; - unsigned long if_send_adptr_bfrs_full; - unsigned long if_send_bfrs_passed_to_adptr; - unsigned long rx_intr_no_socket; - unsigned long rx_intr_dev_not_started; - unsigned long rx_intr_FPIPE_request; - unsigned long rx_intr_DRVSTATS_request; - unsigned long rx_intr_bfr_not_passed_to_stack; - unsigned long rx_intr_bfr_passed_to_stack; - unsigned long UDP_FPIPE_mgmt_kmalloc_err; - unsigned long UDP_FPIPE_mgmt_direction_err; - unsigned long UDP_FPIPE_mgmt_adptr_type_err; - unsigned long UDP_FPIPE_mgmt_adptr_cmnd_OK; - unsigned long UDP_FPIPE_mgmt_adptr_cmnd_timeout; - unsigned long UDP_FPIPE_mgmt_adptr_send_passed; - unsigned long UDP_FPIPE_mgmt_adptr_send_failed; - unsigned long UDP_FPIPE_mgmt_not_passed_to_stack; - unsigned long UDP_FPIPE_mgmt_passed_to_stack; - unsigned long UDP_FPIPE_mgmt_no_socket; - unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; - unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - unsigned long UDP_DRVSTATS_mgmt_adptr_send_passed; - unsigned long UDP_DRVSTATS_mgmt_adptr_send_failed; - unsigned long UDP_DRVSTATS_mgmt_not_passed_to_stack; - unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; - unsigned long UDP_DRVSTATS_mgmt_no_socket; + unsigned char enable_IPX; /* Enable/Disable the use of IPX */ + unsigned long network_number; /* Internal Network Number for IPX*/ + sdla_t *card; /* -> owner */ + unsigned route_flag; /* Add/Rem dest addr in route tables */ + unsigned inarp; /* Inverse Arp Request status */ + int inarp_interval; /* Time between InArp Requests */ + unsigned long inarp_tick; /* InArp jiffies tick counter */ + struct net_device_stats ifstats; /* interface statistics */ + if_send_stat_t drvstats_if_send; + rx_intr_stat_t drvstats_rx_intr; + pipe_mgmt_stat_t drvstats_gen; + + unsigned char usedby; /* Used by WANPIPE or API */ + unsigned long router_up_time; + + unsigned short transmit_length; + char transmit_buffer[FR_MAX_NO_DATA_BYTES_IN_FRAME]; } fr_channel_t; -typedef struct dlci_status { - unsigned short dlci PACKED; - unsigned char state PACKED; +/* Route Flag options */ +#define NO_ROUTE 0x00 +#define ADD_ROUTE 0x01 +#define ROUTE_ADDED 0x02 +#define REMOVE_ROUTE 0x03 + +/* inarp options */ +#define INARP_NONE 0x00 +#define INARP_REQUEST 0x01 +#define INARP_CONFIGURED 0x02 + +/* reasons for enabling the timer interrupt on the adapter */ +#define TMR_INT_ENABLED_UDP 0x01 +#define TMR_INT_ENABLED_UPDATE 0x02 + + +typedef struct dlci_status +{ + unsigned short dlci PACKED; + unsigned char state PACKED; } dlci_status_t; -typedef struct dlci_IB_mapping { - unsigned short dlci PACKED; - unsigned long addr_value PACKED; +typedef struct dlci_IB_mapping +{ + unsigned short dlci PACKED; + unsigned long addr_value PACKED; } dlci_IB_mapping_t; /* This structure is used for DLCI list Tx interrupt mode. It is used to enable interrupt bit and set the packet length for transmission */ +typedef struct fr_dlci_interface +{ + unsigned char gen_interrupt PACKED; + unsigned short packet_length PACKED; + unsigned char reserved PACKED; +} fr_dlci_interface_t; -typedef struct fr_dlci_interface { - unsigned char gen_interrupt PACKED; - unsigned short packet_length PACKED; - unsigned char reserved PACKED; -} fr_dlci_interface_t; - -static unsigned short num_frames; -static unsigned long curr_trace_addr; -static unsigned long start_trace_addr; -static unsigned short available_buffer_space; -static char TracingEnabled; /* variable for keeping track of enabling/disabling FT1 monitor status */ +/* variable for keeping track of enabling/disabling FT1 monitor status */ static int rCount = 0; + +extern int ip_rt_ioctl(unsigned int, void *); extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); @@ -234,70 +253,96 @@ extern void enable_irq(unsigned int); * interrupt test routine */ static int Intr_test_counter; - /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct net_device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct net_device *dev); +static int update(wan_device_t *wandev); +static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, struct net_device *dev); + /* WANPIPE-specific entry points */ static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data); + /* Network device interface */ static int if_init(struct net_device *dev); static int if_open(struct net_device *dev); static int if_close(struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); +static int if_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); static int if_rebuild_hdr(struct sk_buff *skb); static int if_send(struct sk_buff *skb, struct net_device *dev); +static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, + struct sk_buff *skb); static struct net_device_stats *if_stats(struct net_device *dev); + /* Interrupt handlers */ -static void fr502_isr(sdla_t * card); -static void fr508_isr(sdla_t * card); -static void fr502_rx_intr(sdla_t * card); -static void fr508_rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); -static void spur_intr(sdla_t * card); -/* Background polling routines */ -static void wpf_poll(sdla_t * card); +static void fr_isr(sdla_t *card); +static void rx_intr(sdla_t *card); +static void tx_intr(sdla_t *card); +static void timer_intr(sdla_t *card); +static void spur_intr(sdla_t *card); + /* Frame relay firmware interface functions */ -static int fr_read_version(sdla_t * card, char *str); -static int fr_configure(sdla_t * card, fr_conf_t * conf); -static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci); -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu); -static int fr_comm_enable(sdla_t * card); -static int fr_comm_disable(sdla_t * card); -static int fr_get_err_stats(sdla_t * card); -static int fr_get_stats(sdla_t * card); -static int fr_add_dlci(sdla_t * card, int dlci, int num); -static int fr_activate_dlci(sdla_t * card, int dlci, int num); -static int fr_issue_isf(sdla_t * card, int isf); -static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf); -static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf); +static int fr_read_version(sdla_t *card, char *str); +static int fr_configure(sdla_t *card, fr_conf_t *conf); +static int fr_dlci_configure(sdla_t *card, fr_dlc_conf_t *conf, unsigned dlci); +static int fr_init_dlci (sdla_t *card, fr_channel_t *chan); +static int fr_set_intr_mode (sdla_t *card, unsigned mode, unsigned mtu, unsigned short timeout); +static int fr_comm_enable(sdla_t *card); +static int fr_comm_disable(sdla_t *card); +static int fr_get_err_stats(sdla_t *card); +static int fr_get_stats(sdla_t *card); +static int fr_add_dlci(sdla_t *card, int dlci); +static int fr_activate_dlci(sdla_t *card, int dlci); +static int fr_delete_dlci (sdla_t* card, int dlci); +static int fr_issue_isf(sdla_t *card, int isf); +static int fr_send(sdla_t *card, int dlci, unsigned char attr, int len, + void *buf); + /* Firmware asynchronous event handlers */ -static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox); -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox); -static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox); +static int fr_event(sdla_t *card, int event, fr_mbox_t *mbox); +static int fr_modem_failure(sdla_t *card, fr_mbox_t *mbox); +static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox); + /* Miscellaneous functions */ static int update_chan_state(struct net_device *dev); static void set_chan_state(struct net_device *dev, int state); -static struct net_device *find_channel(sdla_t * card, unsigned dlci); -static int is_tx_ready(sdla_t * card, fr_channel_t * chan); +static struct net_device *find_channel(sdla_t *card, unsigned dlci); +static int is_tx_ready(sdla_t *card, fr_channel_t *chan); static unsigned int dec_to_uint(unsigned char *str, int len); -static int reply_udp(unsigned char *data, unsigned int mbox_len); -static int intr_test(sdla_t * card); -static void init_chan_statistics(fr_channel_t * chan); -static void init_global_statistics(sdla_t * card); -static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); + +static int intr_test( sdla_t* card ); +static void init_chan_statistics( fr_channel_t* chan ); +static void init_global_statistics( sdla_t* card ); +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ); +static void setup_for_delayed_transmit(struct net_device* dev, void* buf, + unsigned len); + + +/* Inverse ARP and Dynamic routing functions */ +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev); +int is_arp(void *buf); +int send_inarp_request(sdla_t *card, struct net_device *dev); + /* Udp management functions */ -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan); -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan); -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); +static int process_udp_mgmt_pkt(sdla_t *card); +static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ); +static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, int dlci); + /* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number); +static void switch_net_numbers(unsigned char *sendpacket, + unsigned long network_number, unsigned char incoming); + +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, + unsigned char enable_IPX, unsigned long network_number); + +/* Lock Functions: SMP supported */ +void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags); +void s508_s514_lock(sdla_t *card, unsigned long *smp_flags); + +unsigned short calc_checksum (char *, int); + /****** Public Functions ****************************************************/ @@ -313,154 +358,251 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char * Return: 0 o.k. * < 0 failure. */ -int wpf_init(sdla_t * card, wandev_conf_t * conf) +int wpf_init(sdla_t *card, wandev_conf_t *conf) { - union { + + int err; + + union + { char str[80]; fr_conf_t cfg; } u; + fr_buf_info_t* buf_info; int i; + /* Verify configuration ID */ - if (conf->config_id != WANCONFIG_FR) - { + if (conf->config_id != WANCONFIG_FR) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); + card->devname, conf->config_id); return -EINVAL; + } + /* Initialize protocol-specific fields of adapter data space */ - switch (card->hw.fwid) - { - case SFID_FR502: - card->mbox = (void *) (card->hw.dpmbase + FR502_MBOX_OFFS); - card->rxmb = (void *) (card->hw.dpmbase + FR502_RXMB_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR502_FLAG_OFFS); - card->isr = &fr502_isr; - break; + switch (card->hw.fwid) { + case SFID_FR508: - card->mbox = (void *) (card->hw.dpmbase + FR508_MBOX_OFFS); - card->flags = (void *) (card->hw.dpmbase + FR508_FLAG_OFFS); - card->isr = &fr508_isr; + card->mbox = (void*)(card->hw.dpmbase + + FR508_MBOX_OFFS); + card->flags = (void*)(card->hw.dpmbase + + FR508_FLAG_OFFS); + if(card->hw.type == SDLA_S514) { + card->mbox += FR_MB_VECTOR; + card->flags += FR_MB_VECTOR; + } + card->isr = &fr_isr; break; + default: return -EINVAL; } + /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work * around this, we execute the first command twice. */ + if (fr_read_version(card, NULL) || fr_read_version(card, u.str)) return -EIO; + printk(KERN_INFO "%s: running frame relay firmware v%s\n", - card->devname, u.str); + card->devname, u.str); + /* Adjust configuration */ - conf->mtu = max(min(conf->mtu, 4080), FR_CHANNEL_MTU + FR_HEADER_LEN); + conf->mtu += FR_HEADER_LEN; + conf->mtu = (conf->mtu >= MIN_LGTH_FR_DATA_CFG) ? + min(conf->mtu, FR_MAX_NO_DATA_BYTES_IN_FRAME) : + FR_CHANNEL_MTU + FR_HEADER_LEN; + conf->bps = min(conf->bps, 2048000); - /* Configure adapter firmware */ + + /* Initialze the configuration structure sent to the board to zero */ memset(&u.cfg, 0, sizeof(u.cfg)); - u.cfg.mtu = conf->mtu; - u.cfg.kbps = conf->bps / 1000; - u.cfg.cir_fwd = u.cfg.cir_bwd = 16; - u.cfg.bc_fwd = u.cfg.bc_bwd = 16; - if (conf->station == WANOPT_CPE) - { - u.cfg.options = 0x0080; - printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); - } - else - { - u.cfg.options = 0x0081; - } - switch (conf->u.fr.signalling) - { - case WANOPT_FR_Q933: - u.cfg.options |= 0x0200; + + memset(card->u.f.dlci_to_dev_map, 0, sizeof(card->u.f.dlci_to_dev_map)); + + /* Configure adapter firmware */ + + u.cfg.mtu = conf->mtu; + u.cfg.kbps = conf->bps / 1000; + + u.cfg.cir_fwd = u.cfg.cir_bwd = 16; + u.cfg.bc_fwd = u.cfg.bc_bwd = 16; + + u.cfg.options = 0x0000; + printk(KERN_INFO "%s: Global CIR enabled by Default\n", card->devname); + + switch (conf->u.fr.signalling) { + + case WANOPT_FR_ANSI: + u.cfg.options = 0x0000; + break; + + case WANOPT_FR_Q933: + u.cfg.options |= 0x0200; + break; + + case WANOPT_FR_LMI: + u.cfg.options |= 0x0400; break; - case WANOPT_FR_LMI: - u.cfg.options |= 0x0400; + + case WANOPT_NO: + u.cfg.options |= 0x0800; break; + default: + printk(KERN_INFO "%s: Illegal Signalling option\n", + card->wandev.name); + return -EINVAL; } - if (conf->station == WANOPT_CPE) - { + + + card->wandev.signalling = conf->u.fr.signalling; + + if (conf->station == WANOPT_CPE) { + + + if (conf->u.fr.signalling == WANOPT_NO){ + printk(KERN_INFO + "%s: ERROR - For NO signalling, station must be set to Node!", + card->devname); + return -EINVAL; + } + + u.cfg.station = 0; u.cfg.options |= 0x8000; /* auto config DLCI */ - card->u.f.dlci_num = 0; - } - else - { + card->u.f.dlci_num = 0; + + } else { + u.cfg.station = 1; /* switch emulation mode */ + /* For switch emulation we have to create a list of dlci(s) * that will be sent to be global SET_DLCI_CONFIGURATION * command in fr_configure() routine. */ - card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); - for (i = 0; i < card->u.f.dlci_num; i++) - { - card->u.f.node_dlci[i] = (unsigned short) - conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; + + card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); + + for ( i = 0; i < card->u.f.dlci_num; i++) { + + card->u.f.node_dlci[i] = (unsigned short) + conf->u.fr.dlci[i] ? conf->u.fr.dlci[i] : 16; + } } + if (conf->clocking == WANOPT_INTERNAL) u.cfg.port |= 0x0001; + if (conf->interface == WANOPT_RS232) u.cfg.port |= 0x0002; + if (conf->u.fr.t391) u.cfg.t391 = min(conf->u.fr.t391, 30); else u.cfg.t391 = 5; + if (conf->u.fr.t392) u.cfg.t392 = min(conf->u.fr.t392, 30); else u.cfg.t392 = 15; + if (conf->u.fr.n391) u.cfg.n391 = min(conf->u.fr.n391, 255); else u.cfg.n391 = 2; + if (conf->u.fr.n392) u.cfg.n392 = min(conf->u.fr.n392, 10); else - u.cfg.n392 = 3; + u.cfg.n392 = 3; + if (conf->u.fr.n393) u.cfg.n393 = min(conf->u.fr.n393, 10); else u.cfg.n393 = 4; + if (fr_configure(card, &u.cfg)) return -EIO; - if (card->hw.fwid == SFID_FR508) - { - fr_buf_info_t *buf_info = - (void *) (card->hw.dpmbase + FR508_RXBC_OFFS); - card->rxmb = (void *) (buf_info->rse_next - FR_MB_VECTOR + card->hw.dpmbase); - card->u.f.rxmb_base = (void *) (buf_info->rse_base - FR_MB_VECTOR + card->hw.dpmbase); - card->u.f.rxmb_last = (void *) (buf_info->rse_base + (buf_info->rse_num - 1) * - sizeof(fr_buf_ctl_t) - FR_MB_VECTOR + card->hw.dpmbase); - card->u.f.rx_base = buf_info->buf_base; - card->u.f.rx_top = buf_info->buf_top; - } - card->wandev.mtu = conf->mtu; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->poll = &wpf_poll; - card->exec = &wpf_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.ttl = conf->ttl; - card->wandev.udp_port = conf->udp_port; - card->wandev.enable_tx_int = 0; - card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - card->wandev.enable_IPX = conf->enable_IPX; - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; + + if (card->hw.type == SDLA_S514) { + + buf_info = (void*)(card->hw.dpmbase + FR_MB_VECTOR + + FR508_RXBC_OFFS); + + card->rxmb = (void*)(buf_info->rse_next + card->hw.dpmbase); + + card->u.f.rxmb_base = + (void*)(buf_info->rse_base + card->hw.dpmbase); + + card->u.f.rxmb_last = + (void*)(buf_info->rse_base + + (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) + + card->hw.dpmbase); + } + + else { + buf_info = (void*)(card->hw.dpmbase + FR508_RXBC_OFFS); + + card->rxmb = (void*)(buf_info->rse_next - + FR_MB_VECTOR + card->hw.dpmbase); + + card->u.f.rxmb_base = + (void*)(buf_info->rse_base - + FR_MB_VECTOR + card->hw.dpmbase); + + card->u.f.rxmb_last = + (void*)(buf_info->rse_base + + (buf_info->rse_num - 1) * sizeof(fr_rx_buf_ctl_t) - + FR_MB_VECTOR + card->hw.dpmbase); + } + + card->u.f.rx_base = buf_info->buf_base; + card->u.f.rx_top = buf_info->buf_top; + + card->u.f.tx_interrupts_pending = 0; + + card->wandev.mtu = conf->mtu; + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->poll = NULL; + card->exec = &wpf_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + card->wandev.ttl = conf->ttl; + card->wandev.udp_port = conf->udp_port; + /* Intialize global statistics for a card */ - init_global_statistics(card); - TracingEnabled = 0; - return 0; + init_global_statistics( card ); + + card->TracingEnabled = 0; + + /* Interrupt Test */ + Intr_test_counter = 0; + card->intr_mode = INTR_TEST_MODE; + err = intr_test( card ); + + if (err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { + printk( + "%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + printk( "Please choose another interrupt\n"); + err = -EIO; + return err; + } + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + card->devname, Intr_test_counter); + + + return 0; } /******* WAN Device Driver Entry Points *************************************/ @@ -468,21 +610,38 @@ int wpf_init(sdla_t * card, wandev_conf_t * conf) /*============================================================================ * Update device status & statistics. */ - -static int update(wan_device_t * wandev) +static int update (wan_device_t* wandev) { - sdla_t *card; + volatile sdla_t* card; + unsigned long timeout; + fr508_flags_t* flags; + /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - if (test_and_set_bit(0, (void *) &wandev->critical)) + + if (test_bit(1, (void*)&wandev->critical)) return -EAGAIN; + card = wandev->private; - fr_get_err_stats(card); - fr_get_stats(card); - wandev->critical = 0; + flags = card->flags; + + + card->u.f.update_comms_stats = 1; + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UPDATE; + flags->imask |= FR_INTR_TIMER; + timeout = jiffies; + for(;;) { + if(card->u.f.update_comms_stats == 0) + break; + if ((jiffies - timeout) > (1 * HZ)){ + card->u.f.update_comms_stats = 0; + return -EAGAIN; + } + } return 0; } @@ -498,85 +657,216 @@ static int update(wan_device_t * wandev) * Return: 0 o.k. * < 0 failure (channel will not be created) */ - -static int new_if(wan_device_t * wandev, struct net_device *dev, wanif_conf_t * conf) +static int new_if (wan_device_t* wandev, struct net_device* dev, wanif_conf_t* conf) { - sdla_t *card = wandev->private; - fr_channel_t *chan; + sdla_t* card = wandev->private; + fr_channel_t* chan; + int dlci = 0; int err = 0; - if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) - { + + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); + card->devname); return -EINVAL; } + /* allocate and initialize private data */ chan = kmalloc(sizeof(fr_channel_t), GFP_KERNEL); + if (chan == NULL) return -ENOMEM; + memset(chan, 0, sizeof(fr_channel_t)); strcpy(chan->name, conf->name); chan->card = card; + /* verify media address */ - if (is_digit(conf->addr[0])) - { - int dlci = dec_to_uint(conf->addr, 0); - if (dlci && (dlci <= 4095)) - { + if (is_digit(conf->addr[0])) { + + dlci = dec_to_uint(conf->addr, 0); + + if (dlci && (dlci <= HIGHEST_VALID_DLCI)) { + chan->dlci = dlci; - } - else - { - printk(KERN_ERR "%s: invalid DLCI %u on interface %s!\n", - wandev->name, dlci, chan->name); + + } else { + + printk(KERN_ERR + "%s: invalid DLCI %u on interface %s!\n", + wandev->name, dlci, chan->name); err = -EINVAL; } - } - else - { - printk(KERN_ERR "%s: invalid media address on interface %s!\n", - wandev->name, chan->name); + + } else { + printk(KERN_ERR + "%s: invalid media address on interface %s!\n", + wandev->name, chan->name); err = -EINVAL; } - if (err) - { + + /* Setup wanpipe as a router (WANPIPE) or as an API */ + if(strcmp(conf->usedby, "WANPIPE") == 0){ + printk(KERN_INFO "%s: Running in WANPIPE mode %s\n", + wandev->name, chan->name); + chan->usedby = WANPIPE; + + } else if(strcmp(conf->usedby, "API") == 0){ + +#ifdef FRAME_RELAY_API + chan->usedby = API; + printk(KERN_INFO "%s: Running in API mode %s\n", + wandev->name, chan->name); +#else + printk(KERN_INFO "%s: API Mode is not supported !\n", + wandev->name); + printk(KERN_INFO + "%s: API patch can be obtained from Sangoma Tech.\n", + wandev->name); + err = -EINVAL; +#endif + } + + if (err) { + kfree(chan); return err; } + + card->u.f.dlci_to_dev_map[dlci] = dev; + /* place cir,be,bc and other channel specific information into the * chan structure - */ - if (conf->cir) - { - chan->cir = max(1, min(conf->cir, 512)); - chan->cir_status = CIR_ENABLED; - if (conf->bc) - chan->bc = max(1, min(conf->bc, 512)); - if (conf->be) - chan->be = max(0, min(conf->be, 511)); - } - else + */ + if (conf->cir) { + + chan->cir = max( 1, min( conf->cir, 512 ) ); + chan->cir_status = CIR_ENABLED; + + + /* If CIR is enabled, force BC to equal CIR + * this solves number of potential problems if CIR is + * set and BC is not + */ + chan->bc = chan->cir; + + if (conf->be){ + chan->be = max( 0, min( conf->be, 511) ); + }else{ + conf->be = 0; + } + + printk (KERN_INFO "%s: CIR enabled for DLCI %i \n", + wandev->name,chan->dlci); + printk (KERN_INFO "%s: CIR = %i ; BC = %i ; BE = %i\n", + wandev->name,chan->cir,chan->bc,chan->be); + + + }else{ chan->cir_status = CIR_DISABLED; + printk (KERN_INFO "%s: CIR disabled for DLCI %i\n", + wandev->name,chan->dlci); + } + chan->mc = conf->mc; - chan->dlci_configured = DLCI_NOT_CONFIGURED; - chan->tx_int_status = DISABLED; + + /* FIXME: ARP is not supported by this frame relay verson */ + if (conf->inarp == WANOPT_YES){ + printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support ARPs\n", + card->devname); + + //chan->inarp = conf->inarp ? INARP_REQUEST : INARP_NONE; + //chan->inarp_interval = conf->inarp_interval ? conf->inarp_interval : 10; + kfree(chan); + return -EINVAL; + }else{ + chan->inarp = INARP_NONE; + chan->inarp_interval = 10; + } + + chan->dlci_configured = DLCI_NOT_CONFIGURED; + + + /*FIXME: IPX disabled in this WANPIPE version */ + if (conf->enable_IPX == WANOPT_YES){ + printk(KERN_INFO "%s: ERROR - This version of WANPIPE doesn't support IPX\n", + card->devname); + kfree(chan); + return -EINVAL; + }else{ + chan->enable_IPX = WANOPT_NO; + } + + if (conf->network_number){ + chan->network_number = conf->network_number; + }else{ + chan->network_number = 0xDEADBEEF; + } + + chan->route_flag = NO_ROUTE; + init_chan_statistics(chan); + + chan->transmit_length = 0; + /* prepare network device data space for registration */ dev->name = chan->name; dev->init = &if_init; dev->priv = chan; + + + /* Enable Interrupts and Communications */ + if (!wandev->new_if_cnt){ + fr508_flags_t* flags = card->flags; + + wandev->new_if_cnt++; + + /* + If you enable comms and then set ints, you get a Tx int as you + perform the SET_INT_TRIGGERS command. So, we only set int + triggers and then adjust the interrupt mask (to disable Tx ints) + before enabling comms. + */ + if (fr_set_intr_mode(card, (FR_INTR_RXRDY | FR_INTR_TXRDY | + FR_INTR_DLC | FR_INTR_TIMER | FR_INTR_TX_MULT_DLCIs) , + card->wandev.mtu, 0)) { + kfree(chan); + return -EIO; + } + + flags->imask &= ~(FR_INTR_TXRDY | FR_INTR_TIMER); + + if (fr_comm_enable(card)) { + kfree(chan); + return -EIO; + } + wanpipe_set_state(card, WAN_CONNECTED); + } + return 0; } + /*============================================================================ * Delete logical channel. */ -static int del_if(wan_device_t * wandev, struct net_device *dev) +static int del_if (wan_device_t* wandev, struct net_device* dev) { - if (dev->priv) - { + sdla_t *card = wandev->private; + + /* Execute shutdown very first time we enter del_if */ + + if (!wandev->del_if_cnt) { + wandev->del_if_cnt++; + wanpipe_set_state(card, WAN_DISCONNECTED); + fr_set_intr_mode(card, 0, 0, 0); + fr_comm_disable(card); + } + + if (dev->priv) { kfree(dev->priv); dev->priv = NULL; } + return 0; } @@ -585,41 +875,47 @@ static int del_if(wan_device_t * wandev, struct net_device *dev) /*============================================================================ * Execute adapter interface command. */ -static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data) +static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err, len; fr_cmd_t cmd; - if(copy_from_user((void *) &cmd, u_cmd, sizeof(cmd))) - return -EFAULT; + + if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) + return -EFAULT; + /* execute command */ - do + do { memcpy(&mbox->cmd, &cmd, sizeof(cmd)); - if (cmd.length) - { - if(copy_from_user((void *) &mbox->data, u_data, cmd.length)) + + if (cmd.length){ + if( copy_from_user((void*)&mbox->data, u_data, cmd.length)) return -EFAULT; } + if (sdla_exec(mbox)) err = mbox->cmd.result; - else - return -EIO; - } - while (err && retry-- && fr_event(card, err, mbox)); - /* return result */ + else return -EIO; + + } while (err && retry-- && fr_event(card, err, mbox)); - if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(fr_cmd_t))) + /* return result */ + if (copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) return -EFAULT; + len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) + + if (len && u_data && !copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; return 0; + } /****** Network Device Interface ********************************************/ + /*============================================================================ * Initialize Linux network interface. * @@ -627,35 +923,55 @@ static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data) * interface registration. Returning anything but zero will fail interface * registration. */ -static int if_init(struct net_device *dev) +static int if_init (struct net_device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - wan_device_t *wandev = &card->wandev; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + wan_device_t* wandev = &card->wandev; /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + /* Initialize media-specific parameters */ - dev->type = ARPHRD_DLCI; /* ARP h/w type */ - dev->mtu = FR_CHANNEL_MTU; - dev->hard_header_len = FR_HEADER_LEN; /* media header length */ - dev->addr_len = 2; /* hardware address length */ - *(unsigned short *) dev->dev_addr = htons(chan->dlci); + dev->type = ARPHRD_DLCI; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; + + /* Enable Multicast addressing */ + if (chan->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + + dev->mtu = wandev->mtu - FR_HEADER_LEN; + /* For an API, the maximum number of bytes that the stack will pass + to the driver is (dev->mtu + dev->hard_header_len). So, adjust the + mtu so that a frame of maximum size can be transmitted by the API. + */ + if(chan->usedby == API) { + dev->mtu += (sizeof(api_tx_hdr_t) - FR_HEADER_LEN); + } + + dev->hard_header_len = FR_HEADER_LEN;/* media header length */ + dev->addr_len = 2; /* hardware address length */ + *(unsigned short*)dev->dev_addr = htons(chan->dlci); + /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_start + wandev->msize - 1; - /* Set transmit buffer queue length */ - dev->tx_queue_len = 10; + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + /* Initialize socket buffers */ dev_init_buffers(dev); + set_chan_state(dev, WAN_DISCONNECTED); return 0; } @@ -667,127 +983,62 @@ static int if_init(struct net_device *dev) * * Return 0 if O.k. or errno. */ - -static int if_open(struct net_device *dev) +static int if_open (struct net_device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - struct net_device *dev2; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; int err = 0; - fr508_flags_t *flags = card->flags; struct timeval tv; + if (dev->start) - return -EBUSY; /* only one open is allowed */ - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(1, (void*)&card->wandev.critical)) return -EAGAIN; - if (!card->open_cnt) - { - Intr_test_counter = 0; - card->intr_mode = INTR_TEST_MODE; - err = intr_test(card); - if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { - printk(KERN_INFO - "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n" - ,card->devname, Intr_test_counter); - /* The following allocates and intializes a circular - * link list of interfaces per card. - */ - card->devs_struct = kmalloc(sizeof(load_sharing_t), GFP_KERNEL); - if (card->devs_struct == NULL) - return -ENOMEM; - card->dev_to_devtint_next = card->devs_struct; - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - (card->devs_struct)->dev_ptr = dev2; - if (dev2->slave == NULL) - (card->devs_struct)->next = card->dev_to_devtint_next; - else { - (card->devs_struct)->next = kmalloc( - sizeof(load_sharing_t), GFP_KERNEL); - if ((card->devs_struct)->next == NULL) - return -ENOMEM; - card->devs_struct = (card->devs_struct)->next; - } - } - card->devs_struct = card->dev_to_devtint_next; - card->intr_mode = BUFFER_INTR_MODE; - /* - check all the interfaces for the device to see if CIR has - been enabled for any DLCI(s). If so then use the DLCI list - Interrupt mode for fr_set_intr_mode(), otherwise use the default global interrupt mode - */ - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { - if (((fr_channel_t *) dev2->priv)->cir_status - == CIR_ENABLED) { - card->intr_mode = DLCI_LIST_INTR_MODE; - break; - } - } - /* - If you enable comms and then set ints, you get a Tx int as you - perform the SET_INT_TRIGGERS command. So, we only set int - triggers and then adjust the interrupt mask (to disable Tx ints) before enabling comms. - */ - if (card->intr_mode == BUFFER_INTR_MODE) { - if (fr_set_intr_mode(card, 0x03, card->wandev.mtu)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO - "%s: Global Buffering Tx Interrupt Mode\n" - ,card->devname); - } else if (card->intr_mode == DLCI_LIST_INTR_MODE) { - if (fr_set_intr_mode(card, 0x83, card->wandev.mtu)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - printk(KERN_INFO - "%s: DLCI list Tx Interrupt Mode\n", - card->devname); - } - flags->imask &= ~0x02; - if (fr_comm_enable(card)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - wanpipe_set_state(card, WAN_CONNECTED); - if (card->wandev.station == WANOPT_CPE) { - /* CPE: issue full status enquiry */ - fr_issue_isf(card, FR_ISF_FSE); - } else { /* FR switch: activate DLCI(s) */ - /* For Switch emulation we have to ADD and ACTIVATE - * the DLCI(s) that were configured with the SET_DLCI_ - * CONFIGURATION command. Add and Activate will fail if - * DLCI specified is not included in the list. - * - * Also If_open is called once for each interface. But - * it does not get in here for all the interface. So - * we have to pass the entire list of DLCI(s) to add - * activate routines. - */ - fr_add_dlci(card, - card->u.f.node_dlci[0], card->u.f.dlci_num); - fr_activate_dlci(card, - card->u.f.node_dlci[0], card->u.f.dlci_num); + + + /* If signalling is set to NO, then setup + * DLCI addresses right away. Don't have to wait for + * link to connect. + */ + if (card->wandev.signalling == WANOPT_NO){ + printk(KERN_INFO "%s: Signalling set to NO: Mapping DLCI's\n", + card->wandev.name); + if (fr_init_dlci(card,chan)){ + return -EAGAIN; } } - dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); + + if (card->wandev.station == WANOPT_CPE) { + + /* CPE: issue full status enquiry */ + fr_issue_isf(card, FR_ISF_FSE); + + } else { /* FR switch: activate DLCI(s) */ + + /* For Switch emulation we have to ADD and ACTIVATE + * the DLCI(s) that were configured with the SET_DLCI_ + * CONFIGURATION command. Add and Activate will fail if + * DLCI specified is not included in the list. + * + * Also If_open is called once for each interface. But + * it does not get in here for all the interface. So + * we have to pass the entire list of DLCI(s) to add + * activate routines. + */ + + fr_add_dlci(card, chan->dlci); + fr_activate_dlci(card, chan->dlci); + } + dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; wanpipe_open(card); update_chan_state(dev); - do_gettimeofday(&tv); + do_gettimeofday( &tv ); chan->router_start_time = tv.tv_sec; - card->wandev.critical = 0; + clear_bit(1, (void*)&card->wandev.critical); return err; } @@ -796,22 +1047,21 @@ static int if_open(struct net_device *dev) * o if this is the last open, then disable communications and interrupts. * o reset flags. */ - -static int if_close(struct net_device *dev) +static int if_close (struct net_device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + + if (test_and_set_bit(1, (void*)&card->wandev.critical)) return -EAGAIN; + dev->start = 0; wanpipe_close(card); - if (!card->open_cnt) - { - wanpipe_set_state(card, WAN_DISCONNECTED); - fr_set_intr_mode(card, 0, 0); - fr_comm_disable(card); + if (card->wandev.station == WANOPT_NODE) { + fr_delete_dlci (card,chan->dlci); } - card->wandev.critical = 0; + + clear_bit(1, (void*)&card->wandev.critical); return 0; } @@ -825,15 +1075,15 @@ static int if_close(struct net_device *dev) * * Return: media header length. */ - -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) +static int if_header (struct sk_buff* skb, struct net_device* dev, + unsigned short type, void* daddr, void* saddr, unsigned len) { int hdr_len = 0; + skb->protocol = type; hdr_len = wanrouter_encapsulate(skb, dev); - if (hdr_len < 0) - { + + if (hdr_len < 0) { hdr_len = 0; skb->protocol = 0; } @@ -849,14 +1099,14 @@ static int if_header(struct sk_buff *skb, struct net_device *dev, * Return: 1 physical address resolved. * 0 physical address not resolved */ - -static int if_rebuild_hdr(struct sk_buff *skb) +static int if_rebuild_hdr (struct sk_buff* skb) { - struct net_device *dev=skb->dev; - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; + struct net_device *dev = skb->dev; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); + card->devname, dev->name); return 1; } @@ -864,6 +1114,7 @@ static int if_rebuild_hdr(struct sk_buff *skb) * Send a packet on a network interface. * o set tbusy flag (marks start of the transmission) to block a timer-based * transmit from overlapping. + * o set critical flag when accessing board. * o check link state. If link is not up, then drop the packet. * o check channel status. If it's down then initiate a call. * o pass a packet to corresponding WAN device. @@ -878,876 +1129,951 @@ static int if_rebuild_hdr(struct sk_buff *skb) * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ - -static int if_send(struct sk_buff *skb, struct net_device *dev) +static int if_send (struct sk_buff* skb, struct net_device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - int retry = 0, err; - unsigned char *sendpacket; - struct net_device *dev2; - unsigned long check_braddr, check_mcaddr; - fr508_flags_t *adptr_flags = card->flags; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + int err; + unsigned char *sendpacket; + fr508_flags_t* adptr_flags = card->flags; int udp_type, send_data; - fr_dlci_interface_t *dlci_interface = chan->dlci_int_interface; - unsigned long host_cpu_flags; - ++chan->if_send_entry; + unsigned long smp_flags=0; + void* data; + unsigned len; - if (dev->tbusy) - { - /* If our device stays busy for at least 5 seconds then we will - * kick start the device by making dev->tbusy = 0. We expect - * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. + chan->drvstats_if_send.if_send_entry++; + + if (skb == NULL) { + /* if we get here, some higher layer thinks we've missed an + * tx-done interrupt. */ - ++chan->if_send_busy; + printk(KERN_INFO "%s: interface %s got kicked!\n", + card->devname, dev->name); + chan->drvstats_if_send.if_send_skb_null ++; + mark_bh(NET_BH); + return 0; + } + + /* We must set the 'tbusy' flag if we already have a packet queued for + transmission in the transmit interrupt handler. However, we must + ensure that the transmit interrupt does not reset the 'tbusy' flag + just before we set it, as this will result in a "transmit timeout". + */ + set_bit(2, (void*)&card->wandev.critical); + if(chan->transmit_length) { + dev->tbusy = 1; + chan->tick_counter = jiffies; + clear_bit(2, (void*)&card->wandev.critical); + return 1; + } + clear_bit(2, (void*)&card->wandev.critical); + + if (dev->tbusy) { + + /* If our device stays busy for at least 5 seconds then we will + * kick start the device by making dev->tbusy = 0. We expect + * that our device never stays busy more than 5 seconds. So this + * is only used as a last resort. + */ + + chan->drvstats_if_send.if_send_tbusy++; ++chan->ifstats.collisions; - if ((jiffies - chan->tick_counter) < (5 * HZ)) + + if ((jiffies - chan->tick_counter) < (5 * HZ)) { return 1; + } printk(KERN_INFO "%s: Transmit timed out\n", chan->name); - ++chan->if_send_busy_timeout; - /* unbusy all the interfaces on the card */ - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - dev2->tbusy = 0; - } + chan->drvstats_if_send.if_send_tbusy_timeout ++; + dev->tbusy = 0; + } + + data = skb->data; sendpacket = skb->data; + len = skb->len; + udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) - { - ++chan->if_send_DRVSTATS_request; - process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, 0, - chan); - dev_kfree_skb(skb); - return 0; - } - else if (udp_type == UDP_FPIPE_TYPE) - ++chan->if_send_FPIPE_request; - /* retreive source address in two forms: broadcast & multicast */ - check_braddr = sendpacket[17]; - check_mcaddr = sendpacket[14]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[16]; - check_mcaddr |= sendpacket[15]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[15]; - check_mcaddr |= sendpacket[16]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[14]; - check_mcaddr |= sendpacket[17]; - /* if the Source Address is a Multicast address */ - if ((chan->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) && - (check_mcaddr <= 0xFFFFFFFE)) - { - printk(KERN_INFO "%s: Multicast Src. Addr. silently discarded\n" - ,card->devname); - dev_kfree_skb(skb); - ++chan->ifstats.tx_dropped; - ++chan->if_send_multicast; + + if(udp_type != UDP_INVALID_TYPE) { + if(store_udp_mgmt_pkt(udp_type, UDP_PKT_FRM_STACK, card, skb, + chan->dlci)) { + adptr_flags->imask |= FR_INTR_TIMER; + if (udp_type == UDP_FPIPE_TYPE){ + chan->drvstats_if_send. + if_send_PIPE_request ++; + } + } return 0; } - disable_irq(card->hw.irq); - ++card->irq_dis_if_send_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - if (card->wandev.critical == CRITICAL_IN_ISR) - { - ++chan->if_send_critical_ISR; - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - /* The enable_tx_int flag is set here so that if - * the critical flag is set due to an interrupt - * then we want to enable transmit interrupts - * again. - */ - card->wandev.enable_tx_int = 1; - /* Setting this flag to WAITING_TO_BE_ENABLED - * specifies that interrupt bit has to be - * enabled for that particular interface. - * (delayed interrupt) - */ - chan->tx_int_status = WAITING_TO_BE_ENABLED; - /* This is used for enabling dynamic calculation - * of CIRs relative to the packet length. - */ - chan->pkt_length = skb->len; - dev->tbusy = 1; - chan->tick_counter = jiffies; - } - else - { - card->wandev.enable_tx_int = 1; - dev->tbusy = 1; - chan->tick_counter = jiffies; - } - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return 1; - } - ++chan->if_send_critical_non_ISR; - ++chan->ifstats.tx_dropped; + + if((chan->usedby == API) && (len <= sizeof(api_tx_hdr_t))) { + //FIXME: increment some error statistic + dev_kfree_skb(skb); + return 0; + } + + //FIXME: can we do better than sendpacket[2]? + if ((chan->usedby == WANPIPE) && (sendpacket[2] == 0x45)) { + /* check to see if the source IP address is a broadcast or */ + /* multicast IP address */ + if(chk_bcast_mcast_addr(card, dev, skb)) + return 0; + } + + /* Lock the 508 card: SMP Supported */ + s508_s514_lock(card,&smp_flags); + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + chan->drvstats_if_send.if_send_critical_non_ISR ++; + chan->ifstats.tx_dropped ++; + printk(KERN_INFO "%s Critical in IF_SEND %02X\n", + card->devname, card->wandev.critical); dev_kfree_skb(skb); - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + /* Unlock the 508 card */ + s508_s514_unlock(card,&smp_flags); return 0; } - card->wandev.critical = 0x21; - if (udp_type == UDP_FPIPE_TYPE) - { - err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, - dev, 0, chan); - } - else if (card->wandev.state != WAN_CONNECTED) - { - ++chan->if_send_wan_disconnected; + + if (card->wandev.state != WAN_CONNECTED) { + chan->drvstats_if_send.if_send_wan_disconnected ++; ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } - else if (chan->state != WAN_CONNECTED) - { - ++chan->if_send_dlci_disconnected; + ++card->wandev.stats.tx_dropped; + + } else if (chan->state != WAN_CONNECTED) { + chan->drvstats_if_send.if_send_dlci_disconnected ++; + /* Critical area on 514, since disabl_irq is not used + * thus, interrupt would execute a command at + * the same time as if_send. + */ + set_bit(1, (void*)&card->wandev.critical); update_chan_state(dev); - ++chan->ifstats.tx_dropped; - ++card->wandev.stats.tx_dropped; - } - else if (!is_tx_ready(card, chan)) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = skb->len; - } - dev->tbusy = 1; - chan->tick_counter = jiffies; - adptr_flags->imask |= 0x02; - ++chan->if_send_no_bfrs; - retry = 1; - } - else - { + clear_bit(1, (void*)&card->wandev.critical); + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + + } else if (!is_tx_ready(card, chan)) { + setup_for_delayed_transmit(dev, data, len); + chan->drvstats_if_send.if_send_no_bfrs++; + } else { send_data = 1; - /* If it's an IPX packet */ - if (sendpacket[1] == 0x00 && - sendpacket[2] == 0x80 && - sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) - { - if (card->wandev.enable_IPX) - { - switch_net_numbers(sendpacket, - card->wandev.network_number, 0); - } - else - { - /* increment some statistic here! */ + //FIXME: IPX is not implemented in this version of Frame Relay ? + if((chan->usedby == WANPIPE) && + sendpacket[1] == 0x00 && + sendpacket[2] == 0x80 && + sendpacket[6] == 0x81 && + sendpacket[7] == 0x37) { + + if( chan->enable_IPX ) { + switch_net_numbers(sendpacket, + chan->network_number, 0); + } else { + //FIXME: Take this out when IPX is fixed + printk(KERN_INFO + "%s: WARNING: Unsupported IPX data in send, packet dropped\n", + card->devname); send_data = 0; } } - if (send_data) - { - err = (card->hw.fwid == SFID_FR508) ? - fr508_send(card, chan->dlci, 0, skb->len, skb->data) : - fr502_send(card, chan->dlci, 0, skb->len, skb->data); - if (err) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = skb->len; - } - dev->tbusy = 1; - chan->tick_counter = jiffies; - adptr_flags->imask |= 0x02; - retry = 1; - ++chan->if_send_adptr_bfrs_full; - ++chan->ifstats.tx_errors; - ++card->wandev.stats.tx_errors; + + if (send_data) { + unsigned char attr = 0; + + /* For an API transmission, get rid of the API header */ + if (chan->usedby == API) { + api_tx_hdr_t* api_tx_hdr; + api_tx_hdr = (api_tx_hdr_t*)&skb->data[0x00]; + attr = api_tx_hdr->attr; + data += sizeof(api_tx_hdr_t); + len -= sizeof(api_tx_hdr_t); } - else - { - ++chan->if_send_bfrs_passed_to_adptr; + + err = fr_send(card, chan->dlci, attr, len, data); + if (err) { + switch(err) { + case FRRES_CIR_OVERFLOW: + case FRRES_BUFFER_OVERFLOW: + setup_for_delayed_transmit(dev, data, + len); + chan->drvstats_if_send. + if_send_adptr_bfrs_full ++; + break; + default: + chan->drvstats_if_send. + if_send_dlci_disconnected ++; + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + break; + } + } else { + chan->drvstats_if_send. + if_send_bfr_passed_to_adptr++; ++chan->ifstats.tx_packets; ++card->wandev.stats.tx_packets; - chan->ifstats.tx_bytes += skb->len; - card->wandev.stats.tx_bytes += skb->len; + chan->ifstats.tx_bytes += len; + card->wandev.stats.tx_bytes += len; } } } - if (!retry) + + if (!dev->tbusy) { dev_kfree_skb(skb); + } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return retry; + clear_bit(0, (void*)&card->wandev.critical); + + s508_s514_unlock(card,&smp_flags); + + return (dev->tbusy); +} + + + +/*============================================================================ + * Setup so that a frame can be transmitted on the occurence of a transmit + * interrupt. + */ +static void setup_for_delayed_transmit (struct net_device* dev, void* buf, + unsigned len) +{ + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + fr508_flags_t* adptr_flags = card->flags; + fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; + + if(chan->transmit_length) { + printk(KERN_INFO "%s: Big mess in setup_for_del...\n", + card->devname); + return; + } + + if(len > FR_MAX_NO_DATA_BYTES_IN_FRAME) { + //FIXME: increment some statistic */ + return; + } + + chan->transmit_length = len; + memcpy(chan->transmit_buffer, buf, len); + + dlci_interface->gen_interrupt |= FR_INTR_TXRDY; + dlci_interface->packet_length = len; + adptr_flags->imask |= FR_INTR_TXRDY; + + card->u.f.tx_interrupts_pending ++; +} + + +/*============================================================================ + * Check to see if the packet to be transmitted contains a broadcast or + * multicast source IP address. + * Return 0 if not broadcast/multicast address, otherwise return 1. + */ + +static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, + struct sk_buff *skb) +{ + u32 src_ip_addr; + u32 broadcast_ip_addr = 0; + struct in_device *in_dev; + fr_channel_t* chan = dev->priv; + + /* read the IP source address from the outgoing packet */ + src_ip_addr = *(u32 *)(skb->data + 14); + + /* read the IP broadcast address for the device */ + in_dev = dev->ip_ptr; + if(in_dev != NULL) { + struct in_ifaddr *ifa= in_dev->ifa_list; + if(ifa != NULL) + broadcast_ip_addr = ifa->ifa_broadcast; + else + return 0; + } + + /* check if the IP Source Address is a Broadcast address */ + if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { printk(KERN_INFO + "%s: Broadcast Source Address silently discarded\n", + card->devname); + dev_kfree_skb(skb); + ++ chan->ifstats.tx_dropped; + return 1; + } + + /* check if the IP Source Address is a Multicast address */ + if((chan->mc == WANOPT_NO) && (ntohl(src_ip_addr) >= 0xE0000001) && + (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { + printk(KERN_INFO + "%s: Multicast Source Address silently discarded\n", + card->devname); + dev_kfree_skb(skb); + ++ chan->ifstats.tx_dropped; + return 1; + } + + return 0; } /*============================================================================ * Reply to UDP Management system. * Return nothing. */ - -static int reply_udp(unsigned char *data, unsigned int mbox_len) +static int reply_udp( unsigned char *data, unsigned int mbox_len ) { - unsigned short len, udp_length, temp, i, ip_length; - unsigned long sum; + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + + + fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)data; + /* Set length of packet */ - len = mbox_len + 62; + len = sizeof(fr_encap_hdr_t)+ + sizeof(ip_pkt_t)+ + sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + mbox_len; + + /* fill in UDP reply */ - data[38] = 0x02; + fr_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; + /* fill in UDP length */ - udp_length = mbox_len + 40; + udp_length = sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + mbox_len; + + /* put it on an even boundary */ - if (udp_length & 0x0001) - { + if ( udp_length & 0x0001 ) { udp_length += 1; len += 1; + even_bound = 1; } - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[26], &temp, 2); + + temp = (udp_length<<8)|(udp_length>>8); + fr_udp_pkt->udp_pkt.udp_length = temp; + /* swap UDP ports */ - memcpy(&temp, &data[22], 2); - memcpy(&data[22], &data[24], 2); - memcpy(&data[24], &temp, 2); + temp = fr_udp_pkt->udp_pkt.udp_src_port; + fr_udp_pkt->udp_pkt.udp_src_port = + fr_udp_pkt->udp_pkt.udp_dst_port; + fr_udp_pkt->udp_pkt.udp_dst_port = temp; + + + /* add UDP pseudo header */ temp = 0x1100; - memcpy(&data[udp_length + 22], &temp, 2); - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[udp_length + 24], &temp, 2); + *((unsigned short *) + (fr_udp_pkt->data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *) + (fr_udp_pkt->data+mbox_len+even_bound+2)) = temp; + /* calculate UDP checksum */ - data[28] = data[29] = 0; - sum = 0; - for (i = 0; i < udp_length + 12; i += 2) - { - memcpy(&temp, &data[14 + i], 2); - sum += (unsigned long) temp; - } - while (sum >> 16) - sum = (sum & 0xffffUL) + (sum >> 16); + fr_udp_pkt->udp_pkt.udp_checksum = 0; + + fr_udp_pkt->udp_pkt.udp_checksum = + calc_checksum(&data[UDP_OFFSET+sizeof(fr_encap_hdr_t)], + udp_length+UDP_OFFSET); - temp = (unsigned short) sum; - temp = ~temp; - if (temp == 0) - temp = 0xffff; - memcpy(&data[28], &temp, 2); /* fill in IP length */ - ip_length = udp_length + 20; - temp = (ip_length << 8) | (ip_length >> 8); - memcpy(&data[4], &temp, 2); + ip_length = udp_length + sizeof(ip_pkt_t); + temp = (ip_length<<8)|(ip_length>>8); + fr_udp_pkt->ip_pkt.total_length = temp; + /* swap IP addresses */ - memcpy(&temp, &data[14], 2); - memcpy(&data[14], &data[18], 2); - memcpy(&data[18], &temp, 2); - memcpy(&temp, &data[16], 2); - memcpy(&data[16], &data[20], 2); - memcpy(&data[20], &temp, 2); + ip_temp = fr_udp_pkt->ip_pkt.ip_src_address; + fr_udp_pkt->ip_pkt.ip_src_address = + fr_udp_pkt->ip_pkt.ip_dst_address; + fr_udp_pkt->ip_pkt.ip_dst_address = ip_temp; + + /* fill in IP checksum */ - data[12] = data[13] = 0; - sum = 0; - for (i = 0; i < 20; i += 2) - { - memcpy(&temp, &data[2 + i], 2); - sum += (unsigned long) temp; + fr_udp_pkt->ip_pkt.hdr_checksum = 0; + fr_udp_pkt->ip_pkt.hdr_checksum = + calc_checksum(&data[sizeof(fr_encap_hdr_t)], + sizeof(ip_pkt_t)); + + return len; +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i <len; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; } - while (sum >> 16) + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); - temp = (unsigned short) sum; + } + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if( temp == 0 ) temp = 0xffff; - memcpy(&data[12], &temp, 2); - return len; -} /* reply_udp */ + + return temp; +} + /* If incoming is 0 (outgoing)- if the net numbers is ours make it 0 if incoming is 1 - if the net number is 0 make it ours - */ +*/ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) { unsigned long pnetwork_number; - pnetwork_number = (unsigned long) ((sendpacket[14] << 24) + - (sendpacket[15] << 16) + (sendpacket[16] << 8) + - sendpacket[17]); + + pnetwork_number = (unsigned long)((sendpacket[14] << 24) + + (sendpacket[15] << 16) + (sendpacket[16] << 8) + + sendpacket[17]); + if (!incoming) { /* If the destination network number is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[14] = sendpacket[15] = sendpacket[16] = - sendpacket[17] = 0x00; + if( pnetwork_number == network_number) { + sendpacket[14] = sendpacket[15] = sendpacket[16] = + sendpacket[17] = 0x00; } } else { /* If the incoming network is 0, make it ours */ - if (pnetwork_number == 0) - { - sendpacket[14] = (unsigned char) (network_number >> 24); - sendpacket[15] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[16] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[17] = (unsigned char) (network_number & - 0x000000FF); + if( pnetwork_number == 0) { + sendpacket[14] = (unsigned char)(network_number >> 24); + sendpacket[15] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[16] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[17] = (unsigned char)(network_number & + 0x000000FF); } } - pnetwork_number = (unsigned long) ((sendpacket[26] << 24) + - (sendpacket[27] << 16) + (sendpacket[28] << 8) + - sendpacket[29]); - if (!incoming) { + + + pnetwork_number = (unsigned long)((sendpacket[26] << 24) + + (sendpacket[27] << 16) + (sendpacket[28] << 8) + + sendpacket[29]); + + if( !incoming ) { /* If the source network is ours, make it 0 */ - if (pnetwork_number == network_number) - { - sendpacket[26] = sendpacket[27] = sendpacket[28] = - sendpacket[29] = 0x00; + if( pnetwork_number == network_number) { + sendpacket[26] = sendpacket[27] = sendpacket[28] = + sendpacket[29] = 0x00; } } else { /* If the source network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[26] = (unsigned char) (network_number >> 24); - sendpacket[27] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[28] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[29] = (unsigned char) (network_number & - 0x000000FF); + if( pnetwork_number == 0 ) { + sendpacket[26] = (unsigned char)(network_number >> 24); + sendpacket[27] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[28] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[29] = (unsigned char)(network_number & + 0x000000FF); } } -} /* switch_net_numbers */ +} /* switch_net_numbers */ /*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct net_device_stats. + * Get ethernet-style interface statistics. + * Return a pointer to struct enet_statistics. */ - -static struct net_device_stats *if_stats(struct net_device *dev) +static struct enet_statistics* if_stats (struct net_device* dev) { - fr_channel_t *chan = dev->priv; - if(chan==NULL) + fr_channel_t* chan = dev->priv; + + if(chan == NULL) return NULL; - + return &chan->ifstats; } /****** Interrupt Handlers **************************************************/ -/*============================================================================ - * S502 frame relay interrupt service routine. - */ -static void fr502_isr(sdla_t * card) -{ - fr502_flags_t *flags = card->flags; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ - fr502_rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - flags->imask &= ~0x02; - tx_intr(card); - break; - default: - spur_intr(card); - } - flags->iflag = 0; -} /*============================================================================ * S508 frame relay interrupt service routine. */ - -static void fr508_isr(sdla_t * card) +static void fr_isr (sdla_t* card) { - fr508_flags_t *flags = card->flags; - fr_buf_ctl_t *bctl; + fr508_flags_t* flags = card->flags; char *ptr = &flags->iflag; - struct net_device *dev = card->wandev.dev; - struct net_device *dev2; - int i; - unsigned long host_cpu_flags; - unsigned disable_tx_intr = 1; - fr_channel_t *chan; - fr_dlci_interface_t *dlci_interface; + int i,err; + fr_mbox_t* mbox = card->mbox; + /* This flag prevents nesting of interrupts. See sdla_isr() routine - * in sdlamain.c. + * in sdlamain.c. */ card->in_isr = 1; + ++card->statistics.isr_entry; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag); - ++card->statistics.isr_already_critical; + + if(test_bit(1, (void*)&card->wandev.critical)) { + card->wandev.critical = 0; + flags->iflag = 0; card->in_isr = 0; return; } - /* For all interrupts set the critical flag to CRITICAL_RX_INTR. - * If the if_send routine is called with this flag set it will set - * the enable transmit flag to 1. (for a delayed interrupt) - */ - card->wandev.critical = CRITICAL_IN_ISR; - card->dlci_int_mode_unbusy = 0; - card->buff_int_mode_unbusy = 0; - switch (flags->iflag) - { - case 0x01: /* receive interrupt */ - ++card->statistics.isr_rx; - fr508_rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - ++card->statistics.isr_tx; - bctl = (void *) (flags->tse_offs - FR_MB_VECTOR + - card->hw.dpmbase); - bctl->flag = 0xA0; - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - /* Find the structure and make it unbusy */ - dev = find_channel(card, flags->dlci); - dev->tbusy = 0; - /* This is used to perform devtint at the - * end of the isr - */ - card->dlci_int_mode_unbusy = 1; - /* check to see if any other interfaces are - * busy. If so then do not disable the tx - * interrupts - */ - for (dev2 = card->wandev.dev; dev2; - dev2 = dev2->slave) - { - if (dev2->tbusy == 1) - { - disable_tx_intr = 0; - break; - } - } - if (disable_tx_intr) - flags->imask &= ~0x02; - } - else if (card->intr_mode == BUFFER_INTR_MODE) - { - for (dev2 = card->wandev.dev; dev2; - dev2 = dev2->slave) - { - if (!dev2 || !dev2->start) - { - ++card->statistics.tx_intr_dev_not_started; - continue; - } - if (dev2->tbusy) - { - card->buff_int_mode_unbusy = 1; - ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 1; - dev2->tbusy = 0; - } - else - ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 0; - } - flags->imask &= ~0x02; - } - break; - case 0x08: - Intr_test_counter++; + + if(card->hw.type != SDLA_S514) { + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + printk(KERN_INFO "%s: Critical while in ISR (0x%02X)\n", + card->devname, card->wandev.critical); + ++card->statistics.isr_already_critical; + card->in_isr = 0; + return; + } + } + + switch (flags->iflag) { + + case FR_INTR_RXRDY: /* receive interrupt */ + ++card->statistics.isr_rx; + rx_intr(card); + break; + + + case FR_INTR_TXRDY: /* transmit interrupt */ + ++ card->statistics.isr_tx; + tx_intr(card); + break; + + case FR_INTR_READY: + Intr_test_counter++; ++card->statistics.isr_intr_test; + break; + + case FR_INTR_DLC: /* Event interrupt occured */ + mbox->cmd.command = FR_READ_STATUS; + mbox->cmd.length = 0; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err) + fr_event(card, err, mbox); break; + + case FR_INTR_TIMER: /* Timer interrupt */ + timer_intr(card); + break; + default: - ++card->statistics.isr_spurious; - spur_intr(card); - printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + ++card->statistics.isr_spurious; + spur_intr(card); + printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", + card->devname, flags->iflag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + printk(KERN_INFO "\n"); + break; - } - card->wandev.critical = CRITICAL_INTR_HANDLED; - if (card->wandev.enable_tx_int) - { - if (card->intr_mode == DLCI_LIST_INTR_MODE) - { - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { - chan = dev2->priv; - if (chan->tx_int_status == WAITING_TO_BE_ENABLED) - { - dlci_interface = chan->dlci_int_interface; - dlci_interface->gen_interrupt |= 0x40; - dlci_interface->packet_length = chan->pkt_length; - chan->tx_int_status = DISABLED; - } - } - } - card->wandev.enable_tx_int = 0; - flags->imask |= 0x02; - ++card->statistics.isr_enable_tx_int; - } - save_flags(host_cpu_flags); - cli(); + } + card->in_isr = 0; - card->wandev.critical = 0xD1; flags->iflag = 0; - card->wandev.critical = 0; - restore_flags(host_cpu_flags); - /* Device is now ready to send. The instant this is executed the If_Send - routine is called. That is why this is put at the bottom of the ISR - to prevent a endless loop condition caused by repeated Interrupts and - enable_tx_int flag. - */ - if (card->dlci_int_mode_unbusy) - mark_bh(NET_BH); - if (card->buff_int_mode_unbusy) - { - for (;;) - { - if (((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1) - { - ((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint = 0; - mark_bh(NET_BH); - } - if ((card->devs_struct)->next == card->dev_to_devtint_next) - break; - card->devs_struct = (card->devs_struct)->next; - } - card->devs_struct = (card->dev_to_devtint_next)->next; - card->dev_to_devtint_next = card->devs_struct; - } + if(card->hw.type != SDLA_S514) + clear_bit(0, (void*)&card->wandev.critical); } -/*============================================================================ - * Receive interrupt handler. - */ -static void fr502_rx_intr(sdla_t * card) -{ - fr_mbox_t *mbox = card->rxmb; - struct sk_buff *skb; - struct net_device *dev; - fr_channel_t *chan; - unsigned dlci, len; - void *buf; - unsigned char *sendpacket; - unsigned char buf2[3]; - int udp_type; - sdla_mapmem(&card->hw, FR502_RX_VECTOR); - dlci = mbox->cmd.dlci; - len = mbox->cmd.length; - /* Find network interface for this packet */ - dev = find_channel(card, dlci); - if (dev == NULL) - { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", - card->devname, dlci); - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - chan = dev->priv; - if (!dev->start) - { - ++chan->ifstats.rx_dropped; - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - /* Allocate socket buffer */ - skb = dev_alloc_skb(len); - if (skb == NULL) - { - printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); - ++chan->ifstats.rx_dropped; - sdla_mapmem(&card->hw, FR_MB_VECTOR); - } - /* Copy data to the socket buffer */ - buf = skb_put(skb, len); - memcpy(buf, mbox->data, len); - sdla_mapmem(&card->hw, FR_MB_VECTOR); - /* Check if it's a UDP management packet */ - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - udp_type = udp_pkt_type(skb, card); - if ((udp_type == UDP_FPIPE_TYPE) || (udp_type == UDP_DRVSTATS_TYPE)) - { - if (udp_type == UDP_DRVSTATS_TYPE) - { - ++chan->rx_intr_DRVSTATS_request; - process_udp_driver_call(UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - else - { - ++chan->rx_intr_FPIPE_request; - process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); - } - } - else - { - /* Decapsulate packet and pass it up the protocol stack */ - skb->dev = dev; - buf = skb_pull(skb, 1); /* remove hardware header */ - if (!wanrouter_type_trans(skb, dev)) - { - /* can't decapsulate packet */ - dev_kfree_skb(skb); - ++chan->ifstats.rx_errors; - ++card->wandev.stats.rx_errors; - } - else - { - netif_rx(skb); - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - } - } - sdla_mapmem(&card->hw, FR_MB_VECTOR); -} + + /*============================================================================ * Receive interrupt handler. + * When a receive interrupt occurs do the following: + * 1- Find the structure for the dlci that the interrupt occured on + * 2- If it doesn't exist then print appropriate msg and goto step 8. + * 3- If it exist then copy data to a skb. + * 4- If skb contains Sangoma UDP data then process them + * 5- If skb contains IPXWAN data then send IPXWAN reply packets + * 6- If skb contains Inverse Arp data then send Inv Arp replies + * 7- If skb contains any other data then decapsulate the packet and + * send it to the stack. + * 8- Release the receive element and update receive pointers on the board */ - -static void fr508_rx_intr(sdla_t * card) +static void rx_intr (sdla_t* card) { - fr_buf_ctl_t *frbuf = card->rxmb; - struct sk_buff *skb; - struct net_device *dev; - fr_channel_t *chan; - unsigned dlci, len, offs; - void *buf; - unsigned rx_count = 0; - fr508_flags_t *flags = card->flags; + fr_rx_buf_ctl_t* frbuf = card->rxmb; + fr508_flags_t* flags = card->flags; + fr_channel_t* chan; char *ptr = &flags->iflag; - int i, err, udp_type; - if (frbuf->flag != 0x01) - { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned) frbuf, frbuf->flag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + struct sk_buff* skb; + struct net_device* dev; + void* buf; + unsigned dlci, len, offs, len_incl_hdr; + int i, udp_type; + + if (frbuf->flag != 0x01) { + + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)frbuf, frbuf->flag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); printk(KERN_INFO "\n"); + ++card->statistics.rx_intr_corrupt_rx_bfr; return; } - - do - { - len = frbuf->length; - dlci = frbuf->dlci; - offs = frbuf->offset; - /* Find network interface for this packet */ - dev = find_channel(card, dlci); + + len = frbuf->length; + dlci = frbuf->dlci; + offs = frbuf->offset; + + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + + if (dev == NULL) { + + /* unconfigured DLCI, so discard packet */ + printk(KERN_INFO "%s: received data on unconfigured DLCI %d!\n", + card->devname, dlci); + ++card->statistics.rx_intr_on_orphaned_DLCI; + + } else { chan = dev->priv; - if (dev == NULL) - { - /* Invalid channel, discard packet */ - printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n" - ,card->devname, dlci); - ++card->statistics.rx_intr_on_orphaned_DLCI; - } - else - { - skb = dev_alloc_skb(len); - if (!dev->start || (skb == NULL)) - { - ++chan->ifstats.rx_dropped; - if (dev->start) - { - printk(KERN_INFO - "%s: no socket buffers available!\n", - card->devname); - ++chan->rx_intr_no_socket; - } else - ++chan->rx_intr_dev_not_started; + + skb = dev_alloc_skb(len); + + if (!dev->start || (skb == NULL)) { + ++chan->ifstats.rx_dropped; + + if(dev->start) { + + printk(KERN_INFO + "%s: no socket buffers available!\n", + card->devname); + chan->drvstats_rx_intr.rx_intr_no_socket ++; + + } else + chan->drvstats_rx_intr. + rx_intr_dev_not_started ++; + } else { + /* Copy data to the socket buffer */ + if ((offs + len) > card->u.f.rx_top + 1) { + unsigned tmp = card->u.f.rx_top - offs + 1; + + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, offs, buf, tmp); + offs = card->u.f.rx_base; + len -= tmp; + } + + buf = skb_put(skb, len); + sdla_peek(&card->hw, offs, buf, len); + + udp_type = udp_pkt_type( skb, card ); + + if(udp_type != UDP_INVALID_TYPE) { + if(store_udp_mgmt_pkt(udp_type, + UDP_PKT_FRM_NETWORK, card, skb, dlci)) { + flags->imask |= FR_INTR_TIMER; + if (udp_type == UDP_FPIPE_TYPE){ + chan->drvstats_rx_intr. + rx_intr_PIPE_request ++; + } + } } - else - { - /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top + 1) - { - unsigned tmp = card->u.f.rx_top - offs + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, offs, buf, tmp); - offs = card->u.f.rx_base; - len -= tmp; - } - buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) - { - ++chan->rx_intr_DRVSTATS_request; - process_udp_driver_call( - UDP_PKT_FRM_NETWORK, card, skb, - dev, dlci, chan); + + else if (chan->usedby == API) { + api_rx_hdr_t* api_rx_hdr; + chan->drvstats_rx_intr. + rx_intr_bfr_passed_to_stack ++; + chan->ifstats.rx_packets ++; + card->wandev.stats.rx_packets ++; + chan->ifstats.rx_bytes += skb->len; + card->wandev.stats.rx_bytes += skb->len; + + skb_push(skb, sizeof(api_rx_hdr_t)); + api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; + api_rx_hdr->attr = frbuf->attr; + api_rx_hdr->time_stamp = frbuf->tmstamp; + skb->protocol = htons(0x16); + skb->pkt_type = PACKET_HOST; + /* Pass it up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + netif_rx(skb); + + } else if (handle_IPXWAN(skb->data,chan->name, + chan->enable_IPX, chan->network_number)) { + if (chan->enable_IPX) { + fr_send(card, dlci, 0, skb->len, + skb->data); } - else if (udp_type == UDP_FPIPE_TYPE) - { - ++chan->rx_intr_FPIPE_request; - err = process_udp_mgmt_pkt( - UDP_PKT_FRM_NETWORK, card, - skb, dev, dlci, chan); + dev_kfree_skb(skb); + +/*FIXME: Fix the ARPS in next release + + } else if (is_arp(skb->data)) { + if (process_ARP((arphdr_1490_t *)skb->data, card, dev)) { + printk (KERN_INFO "%s: Error processing ARP Packet.\n", card->devname); } - else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number)) - { - if (card->wandev.enable_IPX) - fr508_send(card, dlci, 0, skb->len, skb->data); - } - else - { - /* Decapsulate packet and pass it up the - protocol stack */ - skb->dev = dev; - /* remove hardware header */ - buf = skb_pull(skb, 1); - if (!wanrouter_type_trans(skb, dev)) - { - /* can't decapsulate packet */ - dev_kfree_skb(skb); - ++chan-> - rx_intr_bfr_not_passed_to_stack; - ++chan-> - ifstats.rx_errors; - ++card-> - wandev.stats.rx_errors; - } - else - { - netif_rx(skb); - ++chan->rx_intr_bfr_passed_to_stack; - ++chan->ifstats.rx_packets; - ++card->wandev.stats.rx_packets; - chan->ifstats.rx_bytes += skb->len; - card->wandev.stats.rx_bytes += skb->len; - } + dev_kfree_skb(skb); +*/ + + } else if ( skb->data[0] != 0x03) { + printk(KERN_INFO "%s: Non IETF packet discarded.\n", card->devname); + dev_kfree_skb(skb); + + } else { + + len_incl_hdr = skb->len; + /* Decapsulate packet and pass it up the + protocol stack */ + skb->dev = dev; + + /* remove hardware header */ + buf = skb_pull(skb, 1); + + if (!wanrouter_type_trans(skb, dev)) { + + /* can't decapsulate packet */ + dev_kfree_skb(skb); + chan->drvstats_rx_intr. + rx_intr_bfr_not_passed_to_stack ++; + ++ chan->ifstats.rx_errors; + ++ card->wandev.stats.rx_errors; + + } else { + netif_rx(skb); + chan->drvstats_rx_intr. + rx_intr_bfr_passed_to_stack ++; + ++ chan->ifstats.rx_packets; + ++ card->wandev.stats.rx_packets; + chan->ifstats.rx_bytes += len_incl_hdr; + card->wandev.stats.rx_bytes += + len_incl_hdr; } - } - } - /* Release buffer element and calculate a pointer to the next - one */ - frbuf->flag = 0; - card->rxmb = ++frbuf; - if ((void *) frbuf > card->u.f.rxmb_last) - card->rxmb = card->u.f.rxmb_base; - /* The loop put in is temporary, that is why the break is - * placed here. (?????) - */ - break; - frbuf = card->rxmb; - } - while (frbuf->flag && ((++rx_count) < 4)); + } + } + } + + /* Release buffer element and calculate a pointer to the next one */ + frbuf->flag = 0; + card->rxmb = ++frbuf; + if ((void*)frbuf > card->u.f.rxmb_last) + card->rxmb = card->u.f.rxmb_base; + } + /*============================================================================ * Transmit interrupt handler. - * o print a warning - * o - * If number of spurious interrupts exceeded some limit, then ??? */ -static void tx_intr(sdla_t * card) +static void tx_intr(sdla_t *card) { - struct net_device *dev = card->wandev.dev; - if (card->intr_mode == BUFFER_INTR_MODE) - { - for (; dev; dev = dev->slave) - { - if (!dev || !dev->start) - { - ++card->statistics.tx_intr_dev_not_started; - continue; + fr508_flags_t* flags = card->flags; + fr_tx_buf_ctl_t* bctl; + struct net_device* dev = card->wandev.dev; + fr_channel_t* chan; + + if(card->hw.type == SDLA_S514){ + bctl = (void*)(flags->tse_offs + card->hw.dpmbase); + }else{ + bctl = (void*)(flags->tse_offs - FR_MB_VECTOR + + card->hw.dpmbase); + } + + /* Find the structure and make it unbusy */ + dev = find_channel(card, flags->dlci); + chan = dev->priv; + + if(!chan->transmit_length) { + printk(KERN_INFO "%s: tx int error - transmit length zero\n", + card->wandev.name); + return; + } + + /* If the 'if_send()' procedure is currently checking the 'tbusy' + status, then we cannot transmit. Instead, we configure the microcode + so as to re-issue this transmit interrupt at a later stage. + */ + if (test_bit(2, (void*)&card->wandev.critical)) { + fr_dlci_interface_t* dlci_interface = chan->dlci_int_interface; + bctl->flag = 0xA0; + dlci_interface->gen_interrupt |= FR_INTR_TXRDY; + printk(KERN_INFO "%s: TX Interrupt Detected busy if_send\n",card->devname); + + } else { + bctl->dlci = flags->dlci; + bctl->length = chan->transmit_length; + sdla_poke(&card->hw, bctl->offset, chan->transmit_buffer, + chan->transmit_length); + bctl->flag = 0xC0; + + ++chan->ifstats.tx_packets; + ++card->wandev.stats.tx_packets; + chan->ifstats.tx_bytes += chan->transmit_length; + card->wandev.stats.tx_bytes += chan->transmit_length; + chan->transmit_length = 0; + + /* if any other interfaces have transmit interrupts pending, */ + /* do not disable the global transmit interrupt */ + if(!(-- card->u.f.tx_interrupts_pending)) + flags->imask &= ~FR_INTR_TXRDY; + + dev->tbusy = 0; + mark_bh(NET_BH); + } +} + + +/*============================================================================ + * Timer interrupt handler. + FIXME: update comments as we modify the code + * The timer interrupt is used for three purposes: + * 1) Processing udp calls from 'fpipemon'. + * 2) Processing update calls from /proc file system + * 2) Reading board-level statistics for updating the proc file system. + * 3) Sending inverse ARP request packets. + */ +static void timer_intr(sdla_t *card) +{ + fr508_flags_t* flags = card->flags; + + if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UDP) { + if(card->u.f.udp_type == UDP_FPIPE_TYPE) { + if(process_udp_mgmt_pkt(card)) { + card->u.f.timer_int_enabled &= + ~TMR_INT_ENABLED_UDP; } - dev->tbusy = 0; - mark_bh(NET_BH); } + } + + if(card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE) { + fr_get_err_stats(card); + fr_get_stats(card); + card->u.f.update_comms_stats = 0; + card->u.f.timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; } - else - { - dev->tbusy = 0; - mark_bh(NET_BH); + + +//FIXME: Fix the dynamic IP addressing +/* +goto L4; + + // Used to send inarp request at given interval + if (card->wandev.state == WAN_CONNECTED) { + int num_remaining = 0; + for (dev=card->wandev.dev;dev;dev=dev->slave) { + fr_channel_t *chan = dev->priv; + + if (chan->inarp == INARP_REQUEST && + chan->state == WAN_CONNECTED) { + num_remaining++; + + if ((jiffies - chan->inarp_tick) > (chan->inarp_interval * HZ)) { + send_inarp_request(card,dev); + chan->inarp_tick = jiffies; + } + } + } + if (!num_remaining) { // no more to process + flags->imask &= ~FR_INTR_TIMER; + } } +L4: + ; +*/ + if(!card->u.f.timer_int_enabled) + flags->imask &= ~FR_INTR_TIMER; } + /*============================================================================ * Spurious interrupt handler. * o print a warning * o - * If number of spurious interrupts exceeded some limit, then ??? */ - -static void spur_intr(sdla_t * card) +static void spur_intr (sdla_t* card) { printk(KERN_INFO "%s: spurious interrupt!\n", card->devname); } -/* - Return 0 for non-IPXWAN packet - 1 for IPXWAN packet or IPX is not enabled! +//FIXME: Fix the IPX in next version +/*=========================================================================== + * Return 0 for non-IPXWAN packet + * 1 for IPXWAN packet or IPX is not enabled! + * FIXME: Use a IPX structure here not offsets */ - static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number) { int i; - if (sendpacket[1] == 0x00 && + + if( sendpacket[1] == 0x00 && sendpacket[2] == 0x80 && sendpacket[6] == 0x81 && - sendpacket[7] == 0x37) - { + sendpacket[7] == 0x37) { + /* It's an IPX packet */ - if (!enable_IPX) { + if(!enable_IPX) { /* Return 1 so we don't pass it up the stack. */ + //FIXME: Take this out when IPX is fixed + printk (KERN_INFO + "%s: WARNING: Unsupported IPX packet received and dropped\n", + devname); return 1; } - } - else - { + } else { /* It's not IPX so return and pass it up the stack. */ return 0; } - if (sendpacket[24] == 0x90 && - sendpacket[25] == 0x04) + + if( sendpacket[24] == 0x90 && + sendpacket[25] == 0x04) { /* It's IPXWAN */ - if (sendpacket[10] == 0x02 && - sendpacket[42] == 0x00) + + if( sendpacket[10] == 0x02 && + sendpacket[42] == 0x00) { /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname); - /* Go through the routing options and answer no to every */ - /* option except Unnumbered RIP/SAP */ - for (i = 49; sendpacket[i] == 0x00; i += 5) + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + /* Go through the routing options and answer no to every + * option except Unnumbered RIP/SAP + */ + for(i = 49; sendpacket[i] == 0x00; i += 5) { /* 0x02 is the option for Unnumbered RIP/SAP */ - if (sendpacket[i + 4] != 0x02) + if( sendpacket[i + 4] != 0x02) { sendpacket[i + 1] = 0; } } + /* Skip over the extended Node ID option */ - if (sendpacket[i] == 0x04) + if( sendpacket[i] == 0x04 ) + { i += 8; - /* We also want to turn off all header compression opt. */ - for (; sendpacket[i] == 0x80;) + } + + /* We also want to turn off all header compression opt. + */ + for(; sendpacket[i] == 0x80 ;) { sendpacket[i + 1] = 0; i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; } + /* Set the packet type to timer response */ sendpacket[42] = 0x01; - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname); + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); } - else if (sendpacket[42] == 0x02) + else if( sendpacket[42] == 0x02 ) { /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + /* Set the packet type to information response */ sendpacket[42] = 0x03; + /* Set the router name */ sendpacket[59] = 'F'; sendpacket[60] = 'P'; @@ -1756,465 +2082,558 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char sendpacket[63] = 'E'; sendpacket[64] = '-'; sendpacket[65] = CVHexToAscii(network_number >> 28); - sendpacket[66] = CVHexToAscii((network_number & 0x0F000000) >> 24); - sendpacket[67] = CVHexToAscii((network_number & 0x00F00000) >> 20); - sendpacket[68] = CVHexToAscii((network_number & 0x000F0000) >> 16); - sendpacket[69] = CVHexToAscii((network_number & 0x0000F000) >> 12); - sendpacket[70] = CVHexToAscii((network_number & 0x00000F00) >> 8); - sendpacket[71] = CVHexToAscii((network_number & 0x000000F0) >> 4); + sendpacket[66] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[67] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[68] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[69] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[70] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[71] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[72] = CVHexToAscii(network_number & 0x0000000F); - for (i = 73; i < 107; i += 1) + for(i = 73; i < 107; i+= 1) + { sendpacket[i] = 0; - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); } else { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); return 0; } + /* Set the WNodeID to our network address */ - sendpacket[43] = (unsigned char) (network_number >> 24); - sendpacket[44] = (unsigned char) ((network_number & 0x00FF0000) >> 16); - sendpacket[45] = (unsigned char) ((network_number & 0x0000FF00) >> 8); - sendpacket[46] = (unsigned char) (network_number & 0x000000FF); + sendpacket[43] = (unsigned char)(network_number >> 24); + sendpacket[44] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[45] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[46] = (unsigned char)(network_number & 0x000000FF); + return 1; } - /* If we get here, its an IPX-data packet so it'll get passed up the stack. */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); + + /* If we get here, its an IPX-data packet so it'll get passed up the + * stack. + * switch the network numbers + */ + switch_net_numbers(sendpacket, network_number ,1); return 0; } - -/****** Background Polling Routines ****************************************/ - /*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thead' to allow for - * time-dependent housekeeping work. - * - * o fetch asynchronous network events. - * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! - */ + * Process Route. + * This routine is called as a polling routine to dynamically add/delete routes + * negotiated by inverse ARP. It is in this "task" because we don't want routes + * to be added while in interrupt context. +*/ -static void wpf_poll(sdla_t * card) +static void process_route (sdla_t* card) { -/* struct net_device* dev = card->wandev.dev; */ - fr508_flags_t *flags = card->flags; - unsigned long host_cpu_flags; - ++card->statistics.poll_entry; - if (((jiffies - card->state_tick) < HZ) || - (card->intr_mode == INTR_TEST_MODE)) - return; - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) - { - ++card->statistics.poll_already_critical; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return; - } - card->wandev.critical = 0x11; - ++card->statistics.poll_processed; - /* This is to be changed later ??? */ - /* - if( dev && dev->tbusy && !(flags->imask & 0x02) ) { - printk(KERN_INFO "%s: Wpf_Poll: tbusy = 0x01, imask = 0x%02X\n", card->devname, flags->imask); - } - */ - if (flags->event) - { - fr_mbox_t *mbox = card->mbox; - int err; - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.command = FR_READ_STATUS; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err) - fr_event(card, err, mbox); - } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - card->state_tick = jiffies; + struct net_device* dev; + struct in_device *in_dev; + struct rtentry route; + int err = 0; + mm_segment_t fs; + + + /* Dynamic Route adding/removing */ + for (dev = card->wandev.dev; dev ; dev = dev->slave) { + if ( ((fr_channel_t*)dev->priv)->route_flag == ADD_ROUTE || + ((fr_channel_t*)dev->priv)->route_flag == REMOVE_ROUTE ) { + fs = get_fs(); + + in_dev = dev->ip_ptr; + + if( in_dev != NULL && in_dev->ifa_list != NULL) { + memset(&route, 0, sizeof(route)); + route.rt_dev = dev->name; + route.rt_flags = 0; + + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_addr.s_addr=in_dev->ifa_list->ifa_address; + ((struct sockaddr_in *) &(route.rt_dst)) -> + sin_family = AF_INET; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_addr.s_addr = 0xFFFFFFFF; + ((struct sockaddr_in *) &(route.rt_genmask)) -> + sin_family = AF_INET; + + switch(((fr_channel_t*)dev->priv)->route_flag) { + + case ADD_ROUTE: + set_fs(get_ds()); /* get user space block */ + err = ip_rt_ioctl( SIOCADDRT, &route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + ((fr_channel_t*)dev->priv)->name, + in_ntoa(in_dev->ifa_list->ifa_address) ); + } + else { + ((fr_channel_t*)dev->priv)-> + route_flag = ROUTE_ADDED; + } + break; + + case REMOVE_ROUTE: + set_fs(get_ds()); /* get user space block */ + err = ip_rt_ioctl( SIOCDELRT, &route); + set_fs(fs); /* restore old block */ + + if (err) { + printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err); + printk(KERN_INFO "%s: Address: %s\n", + dev->name,in_ntoa(in_dev->ifa_list->ifa_address) ); + } else { + printk(KERN_INFO "%s: Removed route.\n", + ((fr_channel_t*)dev->priv)->name); + ((fr_channel_t*)dev->priv)->route_flag = NO_ROUTE; + } + break; + } /* Case Statement */ + } + } /* If ADD/DELETE ROUTE */ + } /* Device 'For' Loop */ + + card->poll = NULL; } + + /****** Frame Relay Firmware-Specific Functions *****************************/ /*============================================================================ * Read firmware code version. * o fill string str with firmware version info. */ - -static int fr_read_version(sdla_t * card, char *str) +static int fr_read_version (sdla_t* card, char* str) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_CODE_VERSION; + mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; } while (err && retry-- && fr_event(card, err, mbox)); - if (!err && str) - { + if (!err && str) { int len = mbox->cmd.length; memcpy(str, mbox->data, len); - str[len] = '\0'; + str[len] = '\0'; } return err; } + /*============================================================================ * Set global configuration. */ - -static int fr_configure(sdla_t * card, fr_conf_t * conf) +static int fr_configure (sdla_t* card, fr_conf_t *conf) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int dlci_num = card->u.f.dlci_num; int err, i; - do + + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); memcpy(mbox->data, conf, sizeof(fr_conf_t)); - if (dlci_num) - for (i = 0; i < dlci_num; ++i) - ((fr_conf_t *) mbox->data)->dlci[i] = - card->u.f.node_dlci[i]; + + if (dlci_num) for (i = 0; i < dlci_num; ++i) + ((fr_conf_t*)mbox->data)->dlci[i] = + card->u.f.node_dlci[i]; + mbox->cmd.command = FR_SET_CONFIG; mbox->cmd.length = - sizeof(fr_conf_t) + dlci_num * sizeof(short); + sizeof(fr_conf_t) + dlci_num * sizeof(short); + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Set DLCI configuration. */ -static int fr_dlci_configure(sdla_t * card, fr_dlc_conf_t * conf, unsigned dlci) +static int fr_dlci_configure (sdla_t* card, fr_dlc_conf_t *conf, unsigned dlci) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); memcpy(mbox->data, conf, sizeof(fr_dlc_conf_t)); - mbox->cmd.dlci = (unsigned short) dlci; + mbox->cmd.dlci = (unsigned short) dlci; mbox->cmd.command = FR_SET_CONFIG; - mbox->cmd.length = 0x0E; + mbox->cmd.length = sizeof(fr_dlc_conf_t); err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry--); + } while (err && retry--); + return err; } /*============================================================================ * Set interrupt mode. */ -static int fr_set_intr_mode(sdla_t * card, unsigned mode, unsigned mtu) +static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu, + unsigned short timeout) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; + fr508_intr_ctl_t* ictl = (void*)mbox->data; int retry = MAX_CMD_RETRY; int err; + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - if (card->hw.fwid == SFID_FR502) - { - fr502_intr_ctl_t *ictl = (void *) mbox->data; - memset(ictl, 0, sizeof(fr502_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - mbox->cmd.length = sizeof(fr502_intr_ctl_t); - } - else - { - fr508_intr_ctl_t *ictl = (void *) mbox->data; - memset(ictl, 0, sizeof(fr508_intr_ctl_t)); - ictl->mode = mode; - ictl->tx_len = mtu; - ictl->irq = card->hw.irq; - mbox->cmd.length = sizeof(fr508_intr_ctl_t); - } + memset(ictl, 0, sizeof(fr508_intr_ctl_t)); + ictl->mode = mode; + ictl->tx_len = mtu; + ictl->irq = card->hw.irq; + + /* indicate timeout on timer */ + if (mode & 0x20) ictl->timeout = timeout; + + mbox->cmd.length = sizeof(fr508_intr_ctl_t); mbox->cmd.command = FR_SET_INTR_MODE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Enable communications. */ -static int fr_comm_enable(sdla_t * card) +static int fr_comm_enable (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_COMM_ENABLE; + mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Disable communications. */ -static int fr_comm_disable(sdla_t * card) +static int fr_comm_disable (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_COMM_DISABLE; + mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + } while (err && retry-- && fr_event(card, err, mbox)); + + retry = MAX_CMD_RETRY; + + do { + mbox->cmd.command = FR_SET_MODEM_STATUS; + mbox->cmd.length = 1; + mbox->data[0] = 0; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Get communications error statistics. */ -static int fr_get_err_stats(sdla_t * card) +static int fr_get_err_stats (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - + + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_ERROR_STATS; + mbox->cmd.length = 0; + mbox->cmd.dlci = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) - { - fr_comm_stat_t *stats = (void *) mbox->data; - card->wandev.stats.rx_over_errors = stats->rx_overruns; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_aborts; - card->wandev.stats.rx_length_errors = stats->rx_too_long; + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + fr_comm_stat_t* stats = (void*)mbox->data; + card->wandev.stats.rx_over_errors = stats->rx_overruns; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_aborts; + card->wandev.stats.rx_length_errors = stats->rx_too_long; card->wandev.stats.tx_aborted_errors = stats->tx_aborts; + } + return err; } + /*============================================================================ * Get statistics. */ -static int fr_get_stats(sdla_t * card) +static int fr_get_stats (sdla_t* card) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - do + + + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_READ_STATISTICS; + mbox->cmd.length = 0; + mbox->cmd.dlci = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) - { - fr_link_stat_t *stats = (void *) mbox->data; + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + fr_link_stat_t* stats = (void*)mbox->data; card->wandev.stats.rx_frame_errors = stats->rx_bad_format; - card->wandev.stats.rx_dropped = stats->rx_dropped + stats->rx_dropped2; + card->wandev.stats.rx_dropped = + stats->rx_dropped + stats->rx_dropped2; } + return err; } + /*============================================================================ * Add DLCI(s) (Access Node only!). * This routine will perform the ADD_DLCIs command for the specified DLCI. */ -static int fr_add_dlci(sdla_t * card, int dlci, int num) +static int fr_add_dlci (sdla_t* card, int dlci) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; - int err, i; - do + int err; + + do { - unsigned short *dlci_list = (void *) mbox->data; - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - for (i = 0; i < num; ++i) - dlci_list[i] = card->u.f.node_dlci[i]; - mbox->cmd.length = num * sizeof(short); + unsigned short* dlci_list = (void*)mbox->data; + + mbox->cmd.length = sizeof(short); + dlci_list[0] = dlci; mbox->cmd.command = FR_ADD_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ * Activate DLCI(s) (Access Node only!). - * This routine will perform the ACTIVATE_DLCIs command with a list of DLCIs. + * This routine will perform the ACTIVATE_DLCIs command with a DLCI number. */ -static int fr_activate_dlci(sdla_t * card, int dlci, int num) +static int fr_activate_dlci (sdla_t* card, int dlci) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; - int err, i; + int err; + do { - unsigned short *dlci_list = (void *) mbox->data; - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - for (i = 0; i < num; ++i) - dlci_list[i] = card->u.f.node_dlci[i]; - mbox->cmd.length = num * sizeof(short); + unsigned short* dlci_list = (void*)mbox->data; + + mbox->cmd.length = sizeof(short); + dlci_list[0] = dlci; mbox->cmd.command = FR_ACTIVATE_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ - * Issue in-channel signalling frame. + * Delete DLCI(s) (Access Node only!). + * This routine will perform the DELETE_DLCIs command with a DLCI number. */ -static int fr_issue_isf(sdla_t * card, int isf) +static int fr_delete_dlci (sdla_t* card, int dlci) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->data[0] = isf; - mbox->cmd.length = 1; - mbox->cmd.command = FR_ISSUE_IS_FRAME; + unsigned short* dlci_list = (void*)mbox->data; + + mbox->cmd.length = sizeof(short); + dlci_list[0] = dlci; + mbox->cmd.command = FR_DELETE_DLCI; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + + + /*============================================================================ - * Send a frame (S502 version). + * Issue in-channel signalling frame. */ -static int fr502_send(sdla_t * card, int dlci, int attr, int len, void *buf) +static int fr_issue_isf (sdla_t* card, int isf) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - - do + + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - memcpy(mbox->data, buf, len); - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; - mbox->cmd.command = FR_WRITE; + mbox->data[0] = isf; + mbox->cmd.length = 1; + mbox->cmd.command = FR_ISSUE_IS_FRAME; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + } while (err && retry-- && fr_event(card, err, mbox)); return err; } + /*============================================================================ - * Send a frame (S508 version). + * Send a frame on a selected DLCI. */ -static int fr508_send(sdla_t * card, int dlci, int attr, int len, void *buf) +static int fr_send (sdla_t* card, int dlci, unsigned char attr, int len, + void *buf) { - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox + 0x800; int retry = MAX_CMD_RETRY; int err; - + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); - mbox->cmd.dlci = dlci; - mbox->cmd.attr = attr; - mbox->cmd.length = len; + mbox->cmd.dlci = dlci; + mbox->cmd.attr = attr; + mbox->cmd.length = len; mbox->cmd.command = FR_WRITE; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); - - if (!err) - { - fr_buf_ctl_t *frbuf = (void *) (*(unsigned long *) mbox->data - - FR_MB_VECTOR + card->hw.dpmbase); + } while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) { + + fr_tx_buf_ctl_t* frbuf; + + if(card->hw.type == SDLA_S514) + frbuf = (void*)(*(unsigned long*)mbox->data + + card->hw.dpmbase); + else + frbuf = (void*)(*(unsigned long*)mbox->data - + FR_MB_VECTOR + card->hw.dpmbase); + sdla_poke(&card->hw, frbuf->offset, buf, len); frbuf->flag = 0x01; } + return err; } /****** Firmware Asynchronous Event Handlers ********************************/ /*============================================================================ - * Main asynchronous event/error handler. + * Main asyncronous event/error handler. * This routine is called whenever firmware command returns non-zero * return code. * * Return zero if previous command has to be cancelled. */ - -static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox) +static int fr_event (sdla_t *card, int event, fr_mbox_t* mbox) { - fr508_flags_t *flags = card->flags; + fr508_flags_t* flags = card->flags; char *ptr = &flags->iflag; int i; - switch (event) - { + + switch (event) { + case FRRES_MODEM_FAILURE: return fr_modem_failure(card, mbox); + case FRRES_CHANNEL_DOWN: + { + struct net_device *dev; + + /* Remove all routes from associated DLCI's */ + for (dev = card->wandev.dev; dev; dev = dev->slave) { + fr_channel_t *chan = dev->priv; + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + card->poll = &process_route; + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + } + wanpipe_set_state(card, WAN_DISCONNECTED); return 1; + } + case FRRES_CHANNEL_UP: + { + struct net_device *dev; + int num_requests = 0; + + /* Remove all routes from associated DLCI's */ + for (dev = card->wandev.dev; dev; dev = dev->slave) { + fr_channel_t *chan = dev->priv; + if( chan->inarp == INARP_REQUEST ){ + num_requests++; + chan->inarp_tick = jiffies; + } + } + + /* Allow timer interrupts */ + if (num_requests) flags->imask |= 0x20; wanpipe_set_state(card, WAN_CONNECTED); return 1; + } + case FRRES_DLCI_CHANGE: return fr_dlci_change(card, mbox); + case FRRES_DLCI_MISMATCH: - printk(KERN_INFO "%s: DLCI list mismatch!\n", - card->devname); + printk(KERN_INFO "%s: DLCI list mismatch!\n", + card->devname); return 1; + case CMD_TIMEOUT: printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, mbox->cmd.command); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + card->devname, mbox->cmd.command); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x18 + i)); + printk(KERN_INFO "\n"); + break; + case FRRES_DLCI_INACTIVE: - printk(KERN_ERR "%s: DLCI %u is inactive!\n", - card->devname, mbox->cmd.dlci); break; + case FRRES_CIR_OVERFLOW: break; case FRRES_BUFFER_OVERFLOW: - break; + break; default: printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - ,card->devname, mbox->cmd.command, event); + , card->devname, mbox->cmd.command, event); } + return 0; } @@ -2223,178 +2642,228 @@ static int fr_event(sdla_t * card, int event, fr_mbox_t * mbox) * * Return zero if previous command has to be cancelled. */ -static int fr_modem_failure(sdla_t * card, fr_mbox_t * mbox) +static int fr_modem_failure (sdla_t *card, fr_mbox_t* mbox) { printk(KERN_INFO "%s: physical link down! (modem error 0x%02X)\n", - card->devname, mbox->data[0]); - switch (mbox->cmd.command) - { + card->devname, mbox->data[0]); + + switch (mbox->cmd.command){ case FR_WRITE: + case FR_READ: return 0; } + return 1; } + /*============================================================================ * Handle DLCI status change. * * Return zero if previous command has to be cancelled. */ -static int fr_dlci_change(sdla_t * card, fr_mbox_t * mbox) +static int fr_dlci_change (sdla_t *card, fr_mbox_t* mbox) { - dlci_status_t *status = (void *) mbox->data; + dlci_status_t* status = (void*)mbox->data; int cnt = mbox->cmd.length / sizeof(dlci_status_t); - fr_dlc_conf_t cfg; fr_channel_t *chan; - struct net_device *dev2; - for (; cnt; --cnt, ++status) - { - unsigned short dlci = status->dlci; - struct net_device *dev = find_channel(card, dlci); - if (dev == NULL) - { - printk(KERN_INFO - "%s: CPE contains unconfigured DLCI= %d\n", - card->devname, dlci); - } - else - { - if (status->state & 0x01) - { + struct net_device* dev2; + + + for (; cnt; --cnt, ++status) { + + unsigned short dlci= status->dlci; + struct net_device* dev = find_channel(card, dlci); + + if (dev == NULL){ + printk(KERN_INFO + "%s: CPE contains unconfigured DLCI= %d\n", + card->devname, dlci); + + printk(KERN_INFO + "%s: unconfigured DLCI %d reported by network\n" + , card->devname, dlci); + + }else{ + if (status->state == FR_LINK_INOPER) { printk(KERN_INFO - "%s: DLCI %u has been deleted!\n", - card->devname, dlci); + "%s: DLCI %u is inactive!\n", + card->devname, dlci); + if (dev && dev->start) set_chan_state(dev, WAN_DISCONNECTED); } - else if (status->state & 0x02) - { + + if (status->state & FR_DLCI_DELETED) { + printk(KERN_INFO - "%s: DLCI %u becomes active!\n", - card->devname, dlci); + "%s: DLCI %u has been deleted!\n", + card->devname, dlci); + + if (dev && dev->start) { + fr_channel_t *chan = dev->priv; + + if (chan->route_flag == ROUTE_ADDED) { + chan->route_flag = REMOVE_ROUTE; + card->poll = &process_route; + } + + if (chan->inarp == INARP_CONFIGURED) { + chan->inarp = INARP_REQUEST; + } + + set_chan_state(dev, WAN_DISCONNECTED); + } + + } else if (status->state & FR_DLCI_ACTIVE) { + chan = dev->priv; + /* This flag is used for configuring specific DLCI(s) when they become active. - */ + */ chan->dlci_configured = DLCI_CONFIG_PENDING; + if (dev && dev->start) set_chan_state(dev, WAN_CONNECTED); + } } } - for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) - { + + for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave){ + chan = dev2->priv; - if (chan->dlci_configured == DLCI_CONFIG_PENDING) - { - memset(&cfg, 0, sizeof(cfg)); - if (chan->cir_status == CIR_DISABLED) - { - cfg.cir_fwd = cfg.cir_bwd = 16; - cfg.bc_fwd = cfg.bc_bwd = 16; - cfg.conf_flags = 0x0001; - printk(KERN_INFO "%s: CIR Disabled for %s\n", - card->devname, chan->name); - } else if (chan->cir_status == CIR_ENABLED) { - cfg.cir_fwd = cfg.cir_bwd = chan->cir; - cfg.bc_fwd = cfg.bc_bwd = chan->bc; - cfg.be_fwd = cfg.be_bwd = chan->be; - cfg.conf_flags = 0x0000; - printk(KERN_INFO "%s: CIR Enabled for %s\n", - card->devname, chan->name); - } - if (fr_dlci_configure(card, &cfg, chan->dlci)) - { - printk(KERN_INFO - "%s: DLCI Configure failed for %d\n", - card->devname, chan->dlci); + + if (chan->dlci_configured == DLCI_CONFIG_PENDING) { + if (fr_init_dlci(card, chan)){ return 1; } - chan->dlci_configured = DLCI_CONFIGURED; - /* Read the interface byte mapping into the channel - structure. - */ - if (card->intr_mode == DLCI_LIST_INTR_MODE) - read_DLCI_IB_mapping(card, chan); } + } return 1; } + + +static int fr_init_dlci (sdla_t *card, fr_channel_t *chan) +{ + fr_dlc_conf_t cfg; + fr508_flags_t* flags = card->flags; + + memset(&cfg, 0, sizeof(cfg)); + + if ( chan->cir_status == CIR_DISABLED) { + + cfg.cir_fwd = cfg.cir_bwd = 16; + cfg.bc_fwd = cfg.bc_bwd = 16; + cfg.conf_flags = 0x0001; + + }else if (chan->cir_status == CIR_ENABLED) { + + cfg.cir_fwd = cfg.cir_bwd = chan->cir; + cfg.bc_fwd = cfg.bc_bwd = chan->bc; + cfg.be_fwd = cfg.be_bwd = chan->be; + cfg.conf_flags = 0x0000; + } + + if (fr_dlci_configure( card, &cfg , chan->dlci)){ + printk(KERN_INFO + "%s: DLCI Configure failed for %d\n", + card->devname, chan->dlci); + return 1; + } + + chan->dlci_configured = DLCI_CONFIGURED; + + /* Allow timer interrupts */ + if( chan->inarp == INARP_REQUEST && card->wandev.state == WAN_CONNECTED) { + chan->inarp_tick = jiffies; + flags->imask |= 0x20; + } + + /* Read the interface byte mapping into the channel + structure. + */ + read_DLCI_IB_mapping( card, chan ); + + return 0; +} /******* Miscellaneous ******************************************************/ /*============================================================================ * Update channel state. */ -static int update_chan_state(struct net_device *dev) +static int update_chan_state (struct net_device* dev) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; - fr_mbox_t *mbox = card->mbox; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; + fr_mbox_t* mbox = card->mbox; int retry = MAX_CMD_RETRY; int err; - int dlci_found = 0; - do + do { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); mbox->cmd.command = FR_LIST_ACTIVE_DLCI; + mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && retry-- && fr_event(card, err, mbox)); + } while (err && retry-- && fr_event(card, err, mbox)); - if (!err) - { - unsigned short *list = (void *) mbox->data; + if (!err) { + + unsigned short* list = (void*)mbox->data; int cnt = mbox->cmd.length / sizeof(short); - for (; cnt; --cnt, ++list) - { - if (*list == chan->dlci) - { - dlci_found = 1; - set_chan_state(dev, WAN_CONNECTED); + + for (; cnt; --cnt, ++list) { + + if (*list == chan->dlci) { + set_chan_state(dev, WAN_CONNECTED); break; } } - if (!dlci_found) - printk(KERN_INFO "%s: DLCI %u is inactive\n", - card->devname, chan->dlci); } - + return err; } + /*============================================================================ * Set channel state. */ -static void set_chan_state(struct net_device *dev, int state) +static void set_chan_state (struct net_device* dev, int state) { - fr_channel_t *chan = dev->priv; - sdla_t *card = chan->card; + fr_channel_t* chan = dev->priv; + sdla_t* card = chan->card; unsigned long flags; - + save_flags(flags); cli(); - - if (chan->state != state) - { - switch (state) - { + + if (chan->state != state) { + + switch (state) { + case WAN_CONNECTED: - printk(KERN_INFO "%s: interface %s connected!\n" - ,card->devname, dev->name); + printk(KERN_INFO + "%s: Interface %s: DLCI %d connected\n", + card->devname, dev->name, chan->dlci); break; + case WAN_CONNECTING: - printk(KERN_INFO - "%s: interface %s connecting...\n", - card->devname, dev->name); + printk(KERN_INFO + "%s: Interface %s: DLCI %d connecting\n", + card->devname, dev->name, chan->dlci); break; + case WAN_DISCONNECTED: - printk(KERN_INFO - "%s: interface %s disconnected!\n", - card->devname, dev->name); + printk (KERN_INFO + "%s: Interface %s: DLCI %d disconnected!\n", + card->devname, dev->name, chan->dlci); break; } + chan->state = state; } + chan->state_tick = jiffies; restore_flags(flags); } @@ -2402,14 +2871,14 @@ static void set_chan_state(struct net_device *dev, int state) /*============================================================================ * Find network device by its channel number. */ -static struct net_device *find_channel(sdla_t * card, unsigned dlci) +static struct net_device* find_channel (sdla_t* card, unsigned dlci) { - struct net_device *dev; - for (dev = card->wandev.dev; dev; dev = dev->slave) - if (((fr_channel_t *) dev->priv)->dlci == dlci) - break; - return dev; + if(dlci > HIGHEST_VALID_DLCI) + return NULL; + + return(card->u.f.dlci_to_dev_map[dlci]); } + /*============================================================================ * Check to see if a frame can be sent. If no transmit buffers available, * enable transmit interrupts. @@ -2417,22 +2886,17 @@ static struct net_device *find_channel(sdla_t * card, unsigned dlci) * Return: 1 - Tx buffer(s) available * 0 - no buffers available */ - -static int is_tx_ready(sdla_t * card, fr_channel_t * chan) +static int is_tx_ready (sdla_t* card, fr_channel_t* chan) { - if (card->hw.fwid == SFID_FR508) - { - unsigned char sb = inb(card->hw.port); - if (sb & 0x02) - return 1; - } - else - { - fr502_flags_t *flags = card->flags; - if (flags->tx_ready) - return 1; - flags->imask |= 0x02; - } + unsigned char sb; + + if(card->hw.type == SDLA_S514) + return 1; + + sb = inb(card->hw.port); + if (sb & 0x02) + return 1; + return 0; } @@ -2440,688 +2904,790 @@ static int is_tx_ready(sdla_t * card, fr_channel_t * chan) * Convert decimal string to unsigned integer. * If len != 0 then only 'len' characters of the string are converted. */ -static unsigned int dec_to_uint(unsigned char *str, int len) +static unsigned int dec_to_uint (unsigned char* str, int len) { unsigned val; - if (!len) + + if (!len) len = strlen(str); + for (val = 0; len && is_digit(*str); ++str, --len) - val = (val * 10) + (*str - (unsigned) '0'); + val = (val * 10) + (*str - (unsigned)'0'); + return val; } + + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, int dlci) +{ + int udp_pkt_stored = 0; + + if(!card->u.f.udp_pkt_lgth &&(skb->len <= MAX_LGTH_UDP_MGNT_PKT)){ + card->u.f.udp_pkt_lgth = skb->len; + card->u.f.udp_type = udp_type; + card->u.f.udp_pkt_src = udp_pkt_src; + card->u.f.udp_dlci = dlci; + memcpy(card->u.f.udp_pkt_data, skb->data, skb->len); + card->u.f.timer_int_enabled |= TMR_INT_ENABLED_UDP; + udp_pkt_stored = 1; + + }else{ + printk(KERN_INFO "ERROR: UDP packet not stored for DLCI %d\n", + dlci); + } + + dev_kfree_skb(skb); + + return(udp_pkt_stored); +} + + /*============================================================================== * Process UDP call of type FPIPE8ND */ - -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan) +static int process_udp_mgmt_pkt(sdla_t* card) { + int c_retry = MAX_CMD_RETRY; - unsigned char *data; unsigned char *buf; - unsigned char buf2[5]; - unsigned int loops, frames, len; - unsigned long data_ptr; - unsigned short real_len, buffer_length; + unsigned char frames; + unsigned int len; + unsigned short buffer_length; struct sk_buff *new_skb; - unsigned char *sendpacket; - fr_mbox_t *mbox = card->mbox; + fr_mbox_t* mbox = card->mbox; int err; struct timeval tv; int udp_mgmt_req_valid = 1; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) - { - printk(KERN_INFO - "%s: Error allocating memory for UDP management cmnd 0x%02X", - card->devname, data[47]); - ++chan->UDP_FPIPE_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[47]) - { - /* FPIPE_ENABLE_TRACE */ - case 0x41: - /* FPIPE_DISABLE_TRACE */ - case 0x42: - /* FPIPE_GET_TRACE_INFO */ - case 0x43: - /* SET FT1 MODE */ - case 0x81: - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { - ++chan->UDP_FPIPE_mgmt_direction_err; + struct net_device* dev; + fr_channel_t* chan; + fr_udp_pkt_t *fr_udp_pkt; + unsigned short num_trc_els; + fr_trc_el_t* ptr_trc_el; + fr_trc_el_t trc_el; + fpipemon_trc_t* fpipemon_trc; + + char udp_pkt_src = card->u.f.udp_pkt_src; + int dlci = card->u.f.udp_dlci; + + /* Find network interface for this packet */ + dev = find_channel(card, dlci); + chan = dev->priv; + + /* If the UDP packet is from the network, we are going to have to + transmit a response. Before doing so, we must check to see that + we are not currently transmitting a frame (in 'if_send()') and + that we are not already in a 'delayed transmit' state. + */ + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + if (test_bit(0, (void*)&card->wandev.critical) || + test_bit(2, (void*)&card->wandev.critical)) { + return 0; + } + if((dev->tbusy) || (card->u.f.tx_interrupts_pending)) { + return 0; + } + } + + fr_udp_pkt = (fr_udp_pkt_t *)card->u.f.udp_pkt_data; + + switch(fr_udp_pkt->cblock.command) { + + case FPIPE_ENABLE_TRACING: + case FPIPE_DISABLE_TRACING: + case FPIPE_GET_TRACE_INFO: + case FR_SET_FT1_MODE: + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + chan->drvstats_gen. + UDP_PIPE_mgmt_direction_err ++; udp_mgmt_req_valid = 0; break; } - /* FPIPE_FT1_READ_STATUS */ - case 0x44: - /* FT1 MONITOR STATUS */ - case 0x80: - if (card->hw.fwid != SFID_FR508) - { - ++chan->UDP_FPIPE_mgmt_adptr_type_err; - udp_mgmt_req_valid = 0; - } - break; + default: break; - } - if (!udp_mgmt_req_valid) - { + } + + if(!udp_mgmt_req_valid) { /* set length to 0 */ - data[48] = data[49] = 0; + fr_udp_pkt->cblock.length = 0; /* set return code */ - data[50] = (card->hw.fwid != SFID_FR508) ? 0x1F : 0xCD; - } - else - { - switch (data[47]) - { - /* FPIPE_ENABLE_TRACE */ - case 0x41: - if (!TracingEnabled) - { - do - { - /* SET_TRACE_CONFIGURATION */ - mbox->cmd.command = 0x60; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = 0x37; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - - if (err) - { - TracingEnabled = 0; - /* set the return code */ - data[50] = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - /* get num_frames */ - sdla_peek(&card->hw, 0x9000, &num_frames, 2); - sdla_peek(&card->hw, 0x9002, &curr_trace_addr,4); - start_trace_addr = curr_trace_addr; - /* MAX_SEND_BUFFER_SIZE - - * sizeof(UDP_MGMT_PACKET) - 41 */ - available_buffer_space = 1926; - /* set return code */ - data[50] = 0; - } - else - { - /* set return code to line trace already - enabled */ - data[50] = 1; - } - mbox->cmd.length = 0; - TracingEnabled = 1; - break; - /* FPIPE_DISABLE_TRACE */ - case 0x42: - if (TracingEnabled) - { - do - { - /* SET_TRACE_CONFIGURATION */ - mbox->cmd.command = 0x60; - mbox->cmd.length = 1; - mbox->cmd.dlci = 0x00; - mbox->data[0] = 0x36; - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); - } - /* set return code */ - data[50] = 0; - mbox->cmd.length = 0; - TracingEnabled = 0; - break; - /* FPIPE_GET_TRACE_INFO */ - case 0x43: - /* Line trace cannot be performed on the 502 */ - if (!TracingEnabled) - { - /* set return code */ - data[50] = 1; + fr_udp_pkt->cblock.result = 0xCD; + } else { + + switch(fr_udp_pkt->cblock.command) { + + case FPIPE_ENABLE_TRACING: + if(!card->TracingEnabled) { + do { + mbox->cmd.command = FR_SET_TRACE_CONFIG; + mbox->cmd.length = 1; + mbox->cmd.dlci = 0x00; + mbox->data[0] = fr_udp_pkt->data[0] | + RESET_TRC; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, + mbox)); + + if(err) { + card->TracingEnabled = 0; + /* set the return code */ + fr_udp_pkt->cblock.result = + mbox->cmd.result; mbox->cmd.length = 0; break; } - buffer_length = 0; - loops = (num_frames < 20) ? num_frames : 20; - for (frames = 0; frames < loops; frames += 1) - { - sdla_peek(&card->hw, curr_trace_addr, &buf2, 1); - /* no data on board so exit */ - if (buf2[0] == 0x00) - break; - /* 1+sizeof(FRAME_DATA) = 9 */ - if ((available_buffer_space - buffer_length) < 9) - { - /* indicate we have more frames on board - and exit */ - data[62] |= 0x02; - break; - } - /* get frame status */ - sdla_peek(&card->hw, curr_trace_addr + 0x05, &data[62 + buffer_length], 1); - /* get time stamp */ - sdla_peek(&card->hw, curr_trace_addr + 0x06, &data[66 + buffer_length], 2); - /* get frame length */ - sdla_peek(&card->hw, curr_trace_addr + 0x01, &data[64 + buffer_length], 2); - /* get pointer to real data */ - sdla_peek(&card->hw, curr_trace_addr + 0x0C,&data_ptr, 4); - /* see if we can fit the frame into the user buffer */ - memcpy(&real_len, &data[64 + buffer_length], 2); - if (data_ptr == 0 || real_len + 8 > available_buffer_space) - { - data[63 + buffer_length] = 0x00; - } - else - { - /* we can take it next time */ - if (available_buffer_space - buffer_length < real_len + 8) - { - data[62] |= 0x02; - break; - } - /* ok, get the frame */ - data[63 + buffer_length] = 0x01; - /* get the data */ - sdla_peek(&card->hw, data_ptr, &data[68 + buffer_length], real_len); - /* zero the opp flag to show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, curr_trace_addr, &buf2, 1); - /* now move onto the next frame */ - curr_trace_addr += 16; - /* check if we passed the last address */ - if (curr_trace_addr >= (start_trace_addr + num_frames * 16)) - curr_trace_addr = start_trace_addr; - /* update buffer length and make sure - its even */ - if (data[63 + buffer_length] == 0x01) - buffer_length += real_len - 1; - /* for the header */ - buffer_length += 8; - if (buffer_length & 0x0001) - buffer_length += 1; - } - } - /* ok now set the total number of frames passed in the - high 5 bits */ - data[62] = (frames << 3) | data[62]; - /* set the data length */ - mbox->cmd.length = buffer_length; - memcpy(&data[48], &buffer_length, 2); - data[50] = 0; - break; - /* FPIPE_FT1_READ_STATUS */ - case 0x44: - sdla_peek(&card->hw, 0xF020, &data[62], 2); - data[48] = 2; - data[49] = 0; - data[50] = 0; - mbox->cmd.length = 2; - break; - /* FPIPE_FLUSH_DRIVER_STATS */ - case 0x48: - init_chan_statistics(chan); - init_global_statistics(card); - mbox->cmd.length = 0; - break; - case 0x49: - do_gettimeofday(&tv); - chan->router_up_time = tv.tv_sec - chan->router_start_time; - *(unsigned long *) &data[62] = chan->router_up_time; - mbox->cmd.length = 4; - break; - /* FPIPE_KILL_BOARD */ - case 0x50: - break; - /* FT1 MONITOR STATUS */ - case 0x80: - if (data[62] == 1) - { - if (rCount++ != 0) - { - data[50] = 0; - mbox->cmd.length = 1; - break; - } - } - /* Disable FT1 MONITOR STATUS */ - if (data[62] == 0) - { - if (--rCount != 0) - { - data[50] = 0; - mbox->cmd.length = 1; - break; - } - } - default: - do - { - memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&mbox->data, &sendpacket[62],mbox->cmd.length); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); + + sdla_peek(&card->hw, NO_TRC_ELEMENTS_OFF, + &num_trc_els, 2); + sdla_peek(&card->hw, BASE_TRC_ELEMENTS_OFF, + &card->u.f.trc_el_base, 4); + card->u.f.curr_trc_el = card->u.f.trc_el_base; + card->u.f.trc_el_last = card->u.f.curr_trc_el + + ((num_trc_els - 1) * + sizeof(fr_trc_el_t)); + + /* Calculate the maximum trace data area in */ + /* the UDP packet */ + card->u.f.trc_bfr_space=(MAX_LGTH_UDP_MGNT_PKT - + sizeof(fr_encap_hdr_t) - + sizeof(ip_pkt_t) - + sizeof(udp_pkt_t) - + sizeof(wp_mgmt_t) - + sizeof(cblock_t)); + + /* set return code */ + fr_udp_pkt->cblock.result = 0; - if (!err) - { - ++chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; - memcpy(data, sendpacket, skb->len); - memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t)); - if (mbox->cmd.length) - { - memcpy(&data[62], &mbox->data,mbox->cmd.length); - } + } else { + /* set return code to line trace already + enabled */ + fr_udp_pkt->cblock.result = 1; + } + + mbox->cmd.length = 0; + card->TracingEnabled = 1; + break; + + + case FPIPE_DISABLE_TRACING: + if(card->TracingEnabled) { + + do { + mbox->cmd.command = FR_SET_TRACE_CONFIG; + mbox->cmd.length = 1; + mbox->cmd.dlci = 0x00; + mbox->data[0] = ~ACTIVATE_TRC; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, mbox)); + } + + /* set return code */ + fr_udp_pkt->cblock.result = 0; + mbox->cmd.length = 0; + card->TracingEnabled = 0; + break; + + case FPIPE_GET_TRACE_INFO: + + /* Line trace cannot be performed on the 502 */ + if(!card->TracingEnabled) { + /* set return code */ + fr_udp_pkt->cblock.result = 1; + mbox->cmd.length = 0; + break; + } + + (void *)ptr_trc_el = card->u.f.curr_trc_el; + + buffer_length = 0; + fr_udp_pkt->data[0x00] = 0x00; + + for(frames = 0; frames < MAX_FRMS_TRACED; frames ++) { + + sdla_peek(&card->hw, (unsigned long)ptr_trc_el, + (void *)&trc_el.flag, + sizeof(fr_trc_el_t)); + if(trc_el.flag == 0x00) { + break; } - else - { - ++chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; + if((card->u.f.trc_bfr_space - buffer_length) + < sizeof(fpipemon_trc_hdr_t)) { + fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; + break; + } + + fpipemon_trc = + (fpipemon_trc_t *)&fr_udp_pkt->data[buffer_length]; + fpipemon_trc->fpipemon_trc_hdr.status = + trc_el.attr; + fpipemon_trc->fpipemon_trc_hdr.tmstamp = + trc_el.tmstamp; + fpipemon_trc->fpipemon_trc_hdr.length = + trc_el.length; + + if(!trc_el.offset || !trc_el.length) { + + fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; + + }else if((trc_el.length + sizeof(fpipemon_trc_hdr_t) + 1) > + (card->u.f.trc_bfr_space - buffer_length)){ + + fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x00; + fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; + + }else { + fpipemon_trc->fpipemon_trc_hdr.data_passed = 0x01; + sdla_peek(&card->hw, trc_el.offset, + fpipemon_trc->data, + trc_el.length); + } + + trc_el.flag = 0x00; + sdla_poke(&card->hw, (unsigned long)ptr_trc_el, + &trc_el.flag, 1); + + ptr_trc_el ++; + if((void *)ptr_trc_el > card->u.f.trc_el_last) + (void*)ptr_trc_el = card->u.f.trc_el_base; + + buffer_length += sizeof(fpipemon_trc_hdr_t); + if(fpipemon_trc->fpipemon_trc_hdr.data_passed) { + buffer_length += trc_el.length; + } + + if(fr_udp_pkt->data[0x00] & MORE_TRC_DATA) { + break; } + } + + if(frames == MAX_FRMS_TRACED) { + fr_udp_pkt->data[0x00] |= MORE_TRC_DATA; } - } - /* Fill UDP TTL */ - data[10] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { - err = fr508_send(card, dlci, 0, len, data); - if (err) - ++chan->UDP_FPIPE_mgmt_adptr_send_passed; + + card->u.f.curr_trc_el = (void *)ptr_trc_el; + + /* set the total number of frames passed */ + fr_udp_pkt->data[0x00] |= + ((frames << 1) & (MAX_FRMS_TRACED << 1)); + + /* set the data length and return code */ + fr_udp_pkt->cblock.length = mbox->cmd.length = buffer_length; + fr_udp_pkt->cblock.result = 0; + break; + + case FPIPE_FT1_READ_STATUS: + sdla_peek(&card->hw, 0xF020, + &fr_udp_pkt->data[0x00] , 2); + fr_udp_pkt->cblock.length = 2; + fr_udp_pkt->cblock.result = 0; + break; + + case FPIPE_FLUSH_DRIVER_STATS: + init_chan_statistics(chan); + init_global_statistics(card); + mbox->cmd.length = 0; + break; + + case FPIPE_ROUTER_UP_TIME: + do_gettimeofday(&tv); + chan->router_up_time = tv.tv_sec - + chan->router_start_time; + *(unsigned long *)&fr_udp_pkt->data = + chan->router_up_time; + mbox->cmd.length = 4; + break; + + + case FR_FT1_STATUS_CTRL: + if(fr_udp_pkt->data[0] == 1) { + if(rCount++ != 0 ){ + fr_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if(fr_udp_pkt->data[0] == 0) { + if( --rCount != 0) { + fr_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + + case FPIPE_DRIVER_STAT_IFSEND: + memcpy(fr_udp_pkt->data, + &chan->drvstats_if_send.if_send_entry, + sizeof(if_send_stat_t)); + mbox->cmd.length = sizeof(if_send_stat_t); + break; + + case FPIPE_DRIVER_STAT_INTR: + memcpy(fr_udp_pkt->data, + &card->statistics.isr_entry, + sizeof(global_stats_t)); + memcpy(&fr_udp_pkt->data[sizeof(global_stats_t)], + &chan->drvstats_rx_intr.rx_intr_no_socket, + sizeof(rx_intr_stat_t)); + mbox->cmd.length = sizeof(global_stats_t) + + sizeof(rx_intr_stat_t); + break; + + case FPIPE_DRIVER_STAT_GEN: + memcpy(fr_udp_pkt->data, + &chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, + sizeof(pipe_mgmt_stat_t)); + + memcpy(&fr_udp_pkt->data[sizeof(pipe_mgmt_stat_t)], + &card->statistics, sizeof(global_stats_t)); + + fr_udp_pkt->cblock.result = 0; + fr_udp_pkt->cblock.length = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + mbox->cmd.length = fr_udp_pkt->cblock.length; + break; + + default: + do { + memcpy(&mbox->cmd, + &fr_udp_pkt->cblock.command, + sizeof(fr_cmd_t)); + if(mbox->cmd.length) { + memcpy(&mbox->data, + (char *)fr_udp_pkt->data, + mbox->cmd.length); + } + + err = sdla_exec(mbox) ? mbox->cmd.result : + CMD_TIMEOUT; + } while (err && c_retry-- && fr_event(card, err, mbox)); + + if(!err) + chan->drvstats_gen. + UDP_PIPE_mgmt_adptr_cmnd_OK ++; + else + chan->drvstats_gen. + UDP_PIPE_mgmt_adptr_cmnd_timeout ++; + + /* copy the result back to our buffer */ + memcpy(&fr_udp_pkt->cblock.command, + &mbox->cmd, sizeof(fr_cmd_t)); + + if(mbox->cmd.length) { + memcpy(&fr_udp_pkt->data, + &mbox->data, mbox->cmd.length); + } + } + } + + /* Fill UDP TTL */ + fr_udp_pkt->ip_pkt.ttl = card->wandev.ttl; + len = reply_udp(card->u.f.udp_pkt_data, mbox->cmd.length); + + if(udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + err = fr_send(card, dlci, 0, len, card->u.f.udp_pkt_data); + if (err) + chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_passed ++; else - ++chan->UDP_FPIPE_mgmt_adptr_send_failed; - dev_kfree_skb(skb); - } - else - { + chan->drvstats_gen.UDP_PIPE_mgmt_adptr_send_failed ++; + } else { /* Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) - { + if((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ buf = skb_put(new_skb, len); - memcpy(buf, data, len); + memcpy(buf, card->u.f.udp_pkt_data, len); + /* Decapsulate packet and pass it up the protocol stack */ new_skb->dev = dev; - buf = skb_pull(new_skb, 1); /* remove hardware header */ - if (!wanrouter_type_trans(new_skb, dev)) - { - ++chan->UDP_FPIPE_mgmt_not_passed_to_stack; + buf = skb_pull(new_skb, 1); /* remove hardware header*/ + + if(!wanrouter_type_trans(new_skb, dev)) { + + chan->drvstats_gen. + UDP_PIPE_mgmt_not_passed_to_stack ++; /* can't decapsulate packet */ dev_kfree_skb(new_skb); - } - else - { - ++chan->UDP_FPIPE_mgmt_passed_to_stack; + } else { + chan->drvstats_gen. + UDP_PIPE_mgmt_passed_to_stack ++; netif_rx(new_skb); - } - } - else - { - ++chan->UDP_FPIPE_mgmt_no_socket; - printk(KERN_INFO - "%s: UDP mgmt cmnd, no socket buffers available!\n", - card->devname); - } - } - kfree(data); - return 0; + } + + } else { + chan->drvstats_gen.UDP_PIPE_mgmt_no_socket ++; + printk(KERN_INFO + "%s: UDP mgmt cmnd, no socket buffers available!\n", + card->devname); + } + } + + card->u.f.udp_pkt_lgth = 0; + + return 1; } + /*============================================================================== - * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ - * TEST_COUNTER times. + * Send Inverse ARP Request */ - -static int intr_test(sdla_t * card) + +int send_inarp_request(sdla_t *card, struct net_device *dev) { - fr_mbox_t *mb = card->mbox; - int err, i; - /* The critical flag is unset here because we want to get into the - ISR without the flag already set. The If_open sets the flag. - */ - card->wandev.critical = 0; - err = fr_set_intr_mode(card, 0x08, card->wandev.mtu); - if (err == CMD_OK) - { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) - { - /* Run command READ_CODE_VERSION */ - memset(&mb->cmd, 0, sizeof(fr_cmd_t)); - mb->cmd.length = 0; - mb->cmd.command = 0x40; - err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) - fr_event(card, err, mb); - } - } - else - { - return err; + arphdr_1490_t *ArpPacket; + arphdr_fr_t *arphdr; + fr_channel_t *chan = dev->priv; + struct in_device *in_dev; + + in_dev = dev->ip_ptr; + + if(in_dev != NULL ) { + + ArpPacket = kmalloc(sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), GFP_ATOMIC); + /* SNAP Header indicating ARP */ + ArpPacket->control = 0x03; + ArpPacket->pad = 0x00; + ArpPacket->NLPID = 0x80; + ArpPacket->OUI[0] = 0; + ArpPacket->OUI[1] = 0; + ArpPacket->OUI[2] = 0; + ArpPacket->PID = 0x0608; + + arphdr = (arphdr_fr_t *)(ArpPacket + 1); // Go to ARP Packet + + /* InARP request */ + arphdr->ar_hrd = 0x0F00; /* Frame Relay HW type */ + arphdr->ar_pro = 0x0008; /* IP Protocol */ + arphdr->ar_hln = 2; /* HW addr length */ + arphdr->ar_pln = 4; /* IP addr length */ + arphdr->ar_op = htons(0x08); /* InARP Request */ + arphdr->ar_sha = 0; /* src HW DLCI - Doesn't matter */ + if(in_dev->ifa_list != NULL) + arphdr->ar_sip = in_dev->ifa_list->ifa_local; /* Local Address */else + arphdr->ar_sip = 0; + arphdr->ar_tha = 0; /* dst HW DLCI - Doesn't matter */ + arphdr->ar_tip = 0; /* Remote Address -- what we want */ + + printk(KERN_INFO "%s: Sending InARP request on DLCI %d.\n", card->devname, chan->dlci); + fr_send(card, chan->dlci, 0, + sizeof(arphdr_1490_t) + sizeof(arphdr_fr_t), + (void *)ArpPacket); + kfree(ArpPacket); } - err = fr_set_intr_mode(card, 0, card->wandev.mtu); - if (err != CMD_OK) - return err; - card->wandev.critical = 1; - return 0; + + return 1; } -/*============================================================================ - * Process UDP call of type DRVSTATS. + + +/*============================================================================== + * Check packet for ARP Type */ -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, int dlci, fr_channel_t * chan) + +int is_arp(void *buf) { - int c_retry = MAX_CMD_RETRY; - unsigned char *sendpacket; - unsigned char buf2[5]; - unsigned char *data; - unsigned char *buf; - unsigned int len; - fr_mbox_t *mbox = card->mbox; - struct sk_buff *new_skb; - int err; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) - { - printk(KERN_INFO - "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" - ,card->devname, data[45]); - ++chan->UDP_DRVSTATS_mgmt_kmalloc_err; + arphdr_1490_t *arphdr = (arphdr_1490_t *)buf; + + if (arphdr->pad == 0x00 && + arphdr->NLPID == 0x80 && + arphdr->PID == 0x0608) return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[47]) - { - case 0x45: - *(unsigned long *) &data[62] = chan->if_send_entry; - *(unsigned long *) &data[66] = chan->if_send_skb_null; - *(unsigned long *) &data[70] = chan->if_send_broadcast; - *(unsigned long *) &data[74] = chan->if_send_multicast; - *(unsigned long *) &data[78] = chan->if_send_critical_ISR; - *(unsigned long *) &data[82] = chan->if_send_critical_non_ISR; - *(unsigned long *) &data[86] = chan->if_send_busy; - *(unsigned long *) &data[90] = chan->if_send_busy_timeout; - *(unsigned long *) &data[94] = chan->if_send_DRVSTATS_request; - *(unsigned long *) &data[98] = chan->if_send_FPIPE_request; - *(unsigned long *) &data[102] = chan->if_send_wan_disconnected; - *(unsigned long *) &data[106] = chan->if_send_dlci_disconnected; - *(unsigned long *) &data[110] = chan->if_send_no_bfrs; - *(unsigned long *) &data[114] = chan->if_send_adptr_bfrs_full; - *(unsigned long *) &data[118] = chan->if_send_bfrs_passed_to_adptr; - *(unsigned long *) &data[120] = card->irq_dis_if_send_count; - mbox->cmd.length = 62; - break; - case 0x46: - *(unsigned long *) &data[62] = card->statistics.isr_entry; - *(unsigned long *) &data[66] = card->statistics.isr_already_critical; - *(unsigned long *) &data[70] = card->statistics.isr_rx; - *(unsigned long *) &data[74] = card->statistics.isr_tx; - *(unsigned long *) &data[78] = card->statistics.isr_intr_test; - *(unsigned long *) &data[82] = card->statistics.isr_spurious; - *(unsigned long *) &data[86] = card->statistics.isr_enable_tx_int; - *(unsigned long *) &data[90] = card->statistics.tx_intr_dev_not_started; - *(unsigned long *) &data[94] = card->statistics.rx_intr_corrupt_rx_bfr; - *(unsigned long *) &data[98] = card->statistics.rx_intr_on_orphaned_DLCI; - *(unsigned long *) &data[102] = chan->rx_intr_no_socket; - *(unsigned long *) &data[106] = chan->rx_intr_dev_not_started; - *(unsigned long *) &data[110] = chan->rx_intr_DRVSTATS_request; - *(unsigned long *) &data[114] = chan->rx_intr_FPIPE_request; - *(unsigned long *) &data[118] = chan->rx_intr_bfr_not_passed_to_stack; - *(unsigned long *) &data[122] = chan->rx_intr_bfr_passed_to_stack; - mbox->cmd.length = 64; - break; - case 0x47: - *(unsigned long *) &data[62] = chan->UDP_FPIPE_mgmt_kmalloc_err; - *(unsigned long *) &data[66] = chan->UDP_FPIPE_mgmt_adptr_type_err; - *(unsigned long *) &data[70] = chan->UDP_FPIPE_mgmt_direction_err; - *(unsigned long *) &data[74] = chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[78] = chan->UDP_FPIPE_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[82] = chan->UDP_FPIPE_mgmt_adptr_send_passed; - *(unsigned long *) &data[86] = chan->UDP_FPIPE_mgmt_adptr_send_failed; - *(unsigned long *) &data[90] = chan->UDP_FPIPE_mgmt_no_socket; - *(unsigned long *) &data[94] = chan->UDP_FPIPE_mgmt_not_passed_to_stack; - *(unsigned long *) &data[98] = chan->UDP_FPIPE_mgmt_passed_to_stack; - *(unsigned long *) &data[102] = chan->UDP_DRVSTATS_mgmt_kmalloc_err; - *(unsigned long *) &data[106] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[110] = chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[114] = chan->UDP_DRVSTATS_mgmt_adptr_send_passed; - *(unsigned long *) &data[118] = chan->UDP_DRVSTATS_mgmt_adptr_send_failed; - *(unsigned long *) &data[122] = chan->UDP_DRVSTATS_mgmt_no_socket; - *(unsigned long *) &data[126] = chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; - *(unsigned long *) &data[130] = chan->UDP_DRVSTATS_mgmt_passed_to_stack; - *(unsigned long *) &data[134] = card->statistics.poll_entry; - *(unsigned long *) &data[138] = card->statistics.poll_already_critical; - *(unsigned long *) &data[142] = card->statistics.poll_processed; - *(unsigned long *) &data[144] = card->irq_dis_poll_count; - mbox->cmd.length = 86; - break; - default: - do - { - memcpy(&mbox->cmd, &sendpacket[47], sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&mbox->data, &sendpacket[62], mbox->cmd.length); - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - } - while (err && c_retry-- && fr_event(card, err, mbox)); + else return 0; +} + +/*============================================================================== + * Process ARP Packet Type + */ + +int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev) +{ + + arphdr_fr_t *arphdr = (arphdr_fr_t *)(ArpPacket + 1); /* Skip header */ + fr_rx_buf_ctl_t* frbuf = card->rxmb; + struct in_device *in_dev; + + + in_dev = dev->ip_ptr; + if( in_dev != NULL && in_dev->ifa_list != NULL) { + switch (ntohs(arphdr->ar_op)) { + + case 0x08: // Inverse ARP request -- Send Reply, add route. - if (!err) - { - ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - memcpy(data, sendpacket, skb->len); - memcpy(&data[47], &mbox->cmd, sizeof(fr_cmd_t)); - if (mbox->cmd.length) - memcpy(&data[62], &mbox->data, mbox->cmd.length); - } - else - { - ++chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Req\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); + printk(KERN_INFO "mask %X\n", in_dev->ifa_list->ifa_mask); + printk(KERN_INFO "local %X\n", in_dev->ifa_list->ifa_local); + return -1; } - } - /* Fill UDP TTL */ - data[10] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) - { - err = fr508_send(card, dlci, 0, len, data); - if (err) - ++chan->UDP_DRVSTATS_mgmt_adptr_send_failed; - else - ++chan->UDP_DRVSTATS_mgmt_adptr_send_passed; - dev_kfree_skb(skb); - } - else - { - /* Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) - { - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - /* Decapsulate packet and pass it up the - protocol stack */ - new_skb->dev = dev; - /* remove hardware header */ - buf = skb_pull(new_skb, 1); - if (!wanrouter_type_trans(new_skb, dev)) + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); + return -1; + } + + arphdr->ar_op = htons(0x09); /* InARP Reply */ + + /* Set addresses */ + arphdr->ar_tip = arphdr->ar_sip; + arphdr->ar_sip = in_dev->ifa_list->ifa_local; + + fr_send(card, frbuf->dlci, 0, frbuf->length, (void *)ArpPacket); + + /* Modify Point-to-Point Address */ { - /* can't decapsulate packet */ - ++chan->UDP_DRVSTATS_mgmt_not_passed_to_stack; - dev_kfree_skb(new_skb); + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + int err; + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = arphdr->ar_tip; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ } - else + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + card->poll = &process_route; + + break; + + case 0x09: // Inverse ARP reply + + /* Check for valid Address */ + printk(KERN_INFO "%s: Recvd PtP addr %s -InArp Reply\n", ((fr_channel_t *)dev->priv)->name, in_ntoa(arphdr->ar_sip)); + + if ((in_dev->ifa_list->ifa_mask & arphdr->ar_sip) != (in_dev->ifa_list->ifa_mask & in_dev->ifa_list->ifa_local)) { + printk(KERN_INFO "%s: Invalid PtP address. InARP ignored.\n", card->devname); + return -1; + } + + if (in_dev->ifa_list->ifa_local == arphdr->ar_sip) { + printk(KERN_INFO "%s: Local addr = PtP addr. InARP ignored.\n", card->devname); + return -1; + } + + /* Modify Point-to-Point Address */ { - ++chan->UDP_DRVSTATS_mgmt_passed_to_stack; - netif_rx(new_skb); + struct ifreq if_info; + struct sockaddr_in *if_data; + mm_segment_t fs = get_fs(); + int err; + + /* Set remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + set_fs(get_ds()); /* get user space block */ + + if_data = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data->sin_addr.s_addr = arphdr->ar_sip; + if_data->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ } + + /* Add Route Flag */ + /* The route will be added in the polling routine so + that it is not interrupt context. */ + + ((fr_channel_t *) dev->priv)->route_flag = ADD_ROUTE; + ((fr_channel_t *) dev->priv)->inarp = INARP_CONFIGURED; + card->poll = &process_route; + + break; + default: // ARP's and RARP's -- Shouldn't happen. } - else - { - ++chan->UDP_DRVSTATS_mgmt_no_socket; - printk(KERN_INFO "%s: UDP mgmt cmnd, no socket buffers available!\n", card->devname); + } + + return 0; +} + + +/*============================================================================== + * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR_ + * TEST_COUNTER times. + */ +static int intr_test( sdla_t* card ) +{ + fr_mbox_t* mb = card->mbox; + int err,i; + + /* The critical flag is unset here because we want to get into the + ISR without the flag already set. The If_open sets the flag. + */ + clear_bit(1, (void*)&card->wandev.critical); + + err = fr_set_intr_mode(card, FR_INTR_READY, card->wandev.mtu, 0 ); + + if (err == CMD_OK) { + + for ( i = 0; i < MAX_INTR_TEST_COUNTER; i++ ) { + /* Run command READ_CODE_VERSION */ + mb->cmd.length = 0; + mb->cmd.command = FR_READ_CODE_VERSION; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + fr_event(card, err, mb); } + + } else { + return err; } - kfree(data); + + err = fr_set_intr_mode( card, 0, card->wandev.mtu, 0 ); + + if( err != CMD_OK ) + return err; + + set_bit(1, (void*)&card->wandev.critical); return 0; } /*============================================================================== - * Determine what type of UDP call it is. DRVSTATS or FPIPE8ND ? + * Determine what type of UDP call it is. FPIPE8ND ? */ - -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) +static int udp_pkt_type( struct sk_buff *skb, sdla_t* card ) { - unsigned char *sendpacket; - unsigned char buf2[5]; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if (sendpacket[2] == 0x45 && /* IP packet */ - sendpacket[11] == 0x11 && /* UDP packet */ - sendpacket[24] == buf2[1] && /* UDP Port */ - sendpacket[25] == buf2[0] && - sendpacket[38] == 0x01) - { - if (sendpacket[30] == 0x46 && /* FPIPE8ND: Signature */ - sendpacket[31] == 0x50 && - sendpacket[32] == 0x49 && - sendpacket[33] == 0x50 && - sendpacket[34] == 0x45 && - sendpacket[35] == 0x38 && - sendpacket[36] == 0x4E && - sendpacket[37] == 0x44) - { - return UDP_FPIPE_TYPE; - } else if (sendpacket[30] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[31] == 0x52 && - sendpacket[32] == 0x56 && - sendpacket[33] == 0x53 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x41 && - sendpacket[36] == 0x54 && - sendpacket[37] == 0x53) - { - return UDP_DRVSTATS_TYPE; - } - else - return UDP_INVALID_TYPE; + fr_udp_pkt_t *fr_udp_pkt = (fr_udp_pkt_t *)skb->data; + + if((fr_udp_pkt->ip_pkt.protocol == UDPMGMT_UDP_PROTOCOL) && + (fr_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45) && + (fr_udp_pkt->udp_pkt.udp_dst_port == + ntohs(card->wandev.udp_port)) && + (fr_udp_pkt->wp_mgmt.request_reply == + UDPMGMT_REQUEST)) { + if(!strncmp(fr_udp_pkt->wp_mgmt.signature, + UDPMGMT_FPIPE_SIGNATURE, 8)) + return UDP_FPIPE_TYPE; } - else - return UDP_INVALID_TYPE; + + return UDP_INVALID_TYPE; } + + /*============================================================================== * Initializes the Statistics values in the fr_channel structure. */ - -void init_chan_statistics(fr_channel_t * chan) +void init_chan_statistics( fr_channel_t* chan) { - chan->if_send_entry = 0; - chan->if_send_skb_null = 0; - chan->if_send_broadcast = 0; - chan->if_send_multicast = 0; - chan->if_send_critical_ISR = 0; - chan->if_send_critical_non_ISR = 0; - chan->if_send_busy = 0; - chan->if_send_busy_timeout = 0; - chan->if_send_FPIPE_request = 0; - chan->if_send_DRVSTATS_request = 0; - chan->if_send_wan_disconnected = 0; - chan->if_send_dlci_disconnected = 0; - chan->if_send_no_bfrs = 0; - chan->if_send_adptr_bfrs_full = 0; - chan->if_send_bfrs_passed_to_adptr = 0; - chan->rx_intr_no_socket = 0; - chan->rx_intr_dev_not_started = 0; - chan->rx_intr_FPIPE_request = 0; - chan->rx_intr_DRVSTATS_request = 0; - chan->rx_intr_bfr_not_passed_to_stack = 0; - chan->rx_intr_bfr_passed_to_stack = 0; - chan->UDP_FPIPE_mgmt_kmalloc_err = 0; - chan->UDP_FPIPE_mgmt_direction_err = 0; - chan->UDP_FPIPE_mgmt_adptr_type_err = 0; - chan->UDP_FPIPE_mgmt_adptr_cmnd_OK = 0; - chan->UDP_FPIPE_mgmt_adptr_cmnd_timeout = 0; - chan->UDP_FPIPE_mgmt_adptr_send_passed = 0; - chan->UDP_FPIPE_mgmt_adptr_send_failed = 0; - chan->UDP_FPIPE_mgmt_not_passed_to_stack = 0; - chan->UDP_FPIPE_mgmt_passed_to_stack = 0; - chan->UDP_FPIPE_mgmt_no_socket = 0; - chan->UDP_DRVSTATS_mgmt_kmalloc_err = 0; - chan->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0; - chan->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0; - chan->UDP_DRVSTATS_mgmt_adptr_send_passed = 0; - chan->UDP_DRVSTATS_mgmt_adptr_send_failed = 0; - chan->UDP_DRVSTATS_mgmt_not_passed_to_stack = 0; - chan->UDP_DRVSTATS_mgmt_passed_to_stack = 0; - chan->UDP_DRVSTATS_mgmt_no_socket = 0; + memset(&chan->drvstats_if_send.if_send_entry, 0, + sizeof(if_send_stat_t)); + memset(&chan->drvstats_rx_intr.rx_intr_no_socket, 0, + sizeof(rx_intr_stat_t)); + memset(&chan->drvstats_gen.UDP_PIPE_mgmt_kmalloc_err, 0, + sizeof(pipe_mgmt_stat_t)); } + /*============================================================================== * Initializes the Statistics values in the Sdla_t structure. */ - -void init_global_statistics(sdla_t * card) +void init_global_statistics( sdla_t* card ) { /* Intialize global statistics for a card */ - card->statistics.isr_entry = 0; - card->statistics.isr_already_critical = 0; - card->statistics.isr_rx = 0; - card->statistics.isr_tx = 0; - card->statistics.isr_intr_test = 0; - card->statistics.isr_spurious = 0; - card->statistics.isr_enable_tx_int = 0; - card->statistics.rx_intr_corrupt_rx_bfr = 0; - card->statistics.rx_intr_on_orphaned_DLCI = 0; - card->statistics.tx_intr_dev_not_started = 0; - card->statistics.poll_entry = 0; - card->statistics.poll_already_critical = 0; - card->statistics.poll_processed = 0; + memset(&card->statistics.isr_entry, 0, sizeof(global_stats_t)); } -static void read_DLCI_IB_mapping(sdla_t * card, fr_channel_t * chan) +static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan ) { - fr_mbox_t *mbox = card->mbox; - int retry = MAX_CMD_RETRY; - dlci_IB_mapping_t *result; - int err, counter, found; - do - { - memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + dlci_IB_mapping_t* result; + int err, counter, found; + + do { mbox->cmd.command = FR_READ_DLCI_IB_MAPPING; + mbox->cmd.length = 0; err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && fr_event(card, err, mbox)); + + if( mbox->cmd.result != 0){ + printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", + chan->name); } - while (err && retry-- && fr_event(card, err, mbox)); - - if (mbox->cmd.result != 0) - printk(KERN_INFO "%s: Read DLCI IB Mapping failed\n", chan->name); counter = mbox->cmd.length / sizeof(dlci_IB_mapping_t); - result = (void *) mbox->data; + result = (void *)mbox->data; + found = 0; - for (; counter; --counter, ++result) - { - if (result->dlci == chan->dlci) - { - printk(KERN_INFO "%s: DLCI= %d, IB addr = %lx for %s\n" - ,card->devname, result->dlci, result->addr_value ,chan->name); + for (; counter; --counter, ++result) { + if ( result->dlci == chan->dlci ) { chan->IB_addr = result->addr_value; - chan->dlci_int_interface = (void *) (card->hw.dpmbase + - (chan->IB_addr & 0x00001FFF)); + if(card->hw.type == SDLA_S514){ + chan->dlci_int_interface = + (void*)(card->hw.dpmbase + + chan->IB_addr); + }else{ + chan->dlci_int_interface = + (void*)(card->hw.dpmbase + + (chan->IB_addr & 0x00001FFF)); + + } found = 1; - break; - } + break; + } } if (!found) - printk(KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", - card->devname, chan->dlci); + printk( KERN_INFO "%s: DLCI %d not found by IB MAPPING cmd\n", + card->devname, chan->dlci); +} + +void s508_s514_lock(sdla_t *card, unsigned long *smp_flags) +{ + + if (card->hw.type != SDLA_S514){ +#ifdef __SMP__ + spin_lock_irqsave(&card->lock, *smp_flags); +#else + disable_irq(card->hw.irq); +#endif + } +#ifdef __SMP__ + else{ + spin_lock(&card->lock); + } +#endif +} + +void s508_s514_unlock(sdla_t *card, unsigned long *smp_flags) +{ + if (card->hw.type != SDLA_S514){ +#ifdef __SMP__ + spin_unlock_irqrestore(&card->lock, *smp_flags); +#else + enable_irq(card->hw.irq); +#endif + } +#ifdef __SMP__ + else{ + spin_unlock(&card->lock); + } +#endif + } /****** End *****************************************************************/ diff --git a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c index d35ac7c18..1b900fc62 100644 --- a/drivers/net/wan/sdla_ppp.c +++ b/drivers/net/wan/sdla_ppp.c @@ -1,21 +1,39 @@ /***************************************************************************** * sdla_ppp.c WANPIPE(tm) Multiprotocol WAN Link Driver. PPP module. * -* Author: Jaspreet Singh <jaspreet@sangoma.com> +* Author: Nenad Corbic <ncorbic@sangoma.com> * -* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. * * 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 the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* Mar 15, 1998 Alan Cox o 2.1.8x basic port. +* +* Oct 25, 1999 Nenad Corbic o Support for 2.0.X kernels +* Moved dynamic route processing into +* a polling routine. +* Oct 07, 1999 Nenad Corbic o Support for S514 PCI card. +* Gideon Hack o UPD and Updates executed using timer interrupt +* Sep 10, 1999 Nenad Corbic o Fixed up the /proc statistics +* Jul 20, 1999 Nenad Corbic o Remove the polling routines and use +* interrupts instead. +* Sep 17, 1998 Jaspreet Singh o Updates for 2.2.X Kernels. +* Aug 13, 1998 Jaspreet Singh o Improved Line Tracing. +* Jun 22, 1998 David Fong o Added remote IP address assignment +* Mar 15, 1998 Alan Cox o 2.1.8x basic port. +* Apr 16, 1998 Jaspreet Singh o using htons() for the IPX protocol. +* Dec 09, 1997 Jaspreet Singh o Added PAP and CHAP. +* o Implemented new routines like +* ppp_set_inbnd_auth(), ppp_set_outbnd_auth(), +* tokenize() and strstrip(). * Nov 27, 1997 Jaspreet Singh o Added protection against enabling of irqs * while they have been disabled. * Nov 24, 1997 Jaspreet Singh o Fixed another RACE condition caused by * disabling and enabling of irqs. -* o Added new counters for stats on disable/enable* IRQs. +* o Added new counters for stats on disable/enable +* IRQs. * Nov 10, 1997 Jaspreet Singh o Initialized 'skb->mac.raw' to 'skb->data' * before every netif_rx(). * o Free up the device structure in del_if(). @@ -56,6 +74,7 @@ * Jan 06, 1997 Gene Kozin Initial version. *****************************************************************************/ +#include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ @@ -65,10 +84,15 @@ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <linux/if_arp.h> /* ARPHRD_* defines */ #include <asm/byteorder.h> /* htons(), etc. */ -#include <asm/uaccess.h> /* copyto/from user */ -#define _GNUC_ -#include <linux/sdla_ppp.h> /* PPP firmware API definitions */ +#include <linux/in.h> /* sockaddr_in */ +#include <linux/inet.h> /* in_aton(), in_ntoa() prototypes */ + +#include <linux/inetdevice.h> +#include <asm/uaccess.h> +#include <linux/if.h> +#include <linux/sdla_ppp.h> /* PPP firmware API definitions */ +#include <linux/sdlasfm.h> /* S514 Type Definition */ /****** Defines & Macros ****************************************************/ #ifdef _DEBUG_ @@ -76,130 +100,183 @@ #else #define STATIC static #endif -#define PPP_DFLT_MTU 1500 /* default MTU */ -#define PPP_MAX_MTU 4000 /* maximum MTU */ + +#define PPP_DFLT_MTU 1500 /* default MTU */ +#define PPP_MAX_MTU 4000 /* maximum MTU */ #define PPP_HDR_LEN 1 -#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ -#define HOLD_DOWN_TIME (30*HZ) /* link hold down time */ + +#define CONNECT_TIMEOUT (90*HZ) /* link connection timeout */ +#define HOLD_DOWN_TIME (5*HZ) /* link hold down time : Changed from 30 to 5 */ /* For handle_IPXWAN() */ #define CVHexToAscii(b) (((unsigned char)(b) > (unsigned char)9) ? ((unsigned char)'A' + ((unsigned char)(b) - (unsigned char)10)) : ((unsigned char)'0' + (unsigned char)(b))) +/* Macro for enabling/disabling debugging comments */ +//#define NEX_DEBUG +#ifdef NEX_DEBUG +#define NEX_PRINTK(format, a...) printk(format, ## a) +#else +#define NEX_PRINTK(format, a...) +#endif /* NEX_DEBUG */ + +#define DCD(a) ( a & 0x08 ? "HIGH" : "LOW" ) +#define CTS(a) ( a & 0x20 ? "HIGH" : "LOW" ) +#define LCP(a) ( a == 0x09 ? "OPEN" : "CLOSED" ) +#define IP(a) ( a == 0x09 ? "ENABLED" : "DISABLED" ) + +#define TMR_INT_ENABLED_UPDATE 1 +#define TMR_INT_ENABLED_PPP_EVENT 2 +#define TMR_INT_ENABLED_UDP 4 + +/* Set Configuraton Command Definitions */ +#define PERCENT_TX_BUFF 60 +#define TIME_BETWEEN_CONF_REQ 30 +#define TIME_BETWEEN_PAP_CHAP_REQ 30 +#define WAIT_PAP_CHAP_WITHOUT_REPLY 300 +#define WAIT_AFTER_DCD_CTS_LOW 5 +#define TIME_DCD_CTS_LOW_AFTER_LNK_DOWN 10 +#define WAIT_DCD_HIGH_AFTER_ENABLE_COMM 900 +#define MAX_CONF_REQ_WITHOUT_REPLY 10 +#define MAX_TERM_REQ_WITHOUT_REPLY 2 +#define NUM_CONF_NAK_WITHOUT_REPLY 5 +#define NUM_AUTH_REQ_WITHOUT_REPLY 10 + +#define END_OFFSET 0x1F0 +#if LINUX_VERSION_CODE < 0x020125 +#define test_and_set_bit set_bit +#endif + /******Data Structures*****************************************************/ + /* This structure is placed in the private data area of the device structure. * The card structure used to occupy the private area but now the following * structure will incorporate the card structure along with PPP specific data */ - -typedef struct ppp_private_area + +typedef struct ppp_private_area { - sdla_t *card; + sdla_t* card; unsigned long router_start_time; /*router start time in sec */ - unsigned long tick_counter; /*used for 5 second counter */ - unsigned mc; /*multicast support on or off */ + unsigned long tick_counter; /*used for 5 second counter*/ + unsigned mc; /*multicast support on or off*/ + unsigned char enable_IPX; + unsigned long network_number; + unsigned char pap; + unsigned char chap; + unsigned char sysname[31]; /* system name for in-bnd auth*/ + unsigned char userid[511]; /* list of user ids */ + unsigned char passwd[511]; /* list of passwords */ + unsigned protocol; /* SKB Protocol */ + u32 ip_local; /* Local IP Address */ + u32 ip_remote; /* remote IP Address */ + + unsigned char timer_int_enabled; /* Who enabled the timer inter*/ + unsigned char update_comms_stats; /* Used by update function */ + unsigned long curr_trace_addr; /* Trace information */ + unsigned long start_trace_addr; + unsigned long end_trace_addr; + + unsigned short udp_pkt_lgth; + char udp_pkt_src; + char udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT]; + /* PPP specific statistics */ - unsigned long if_send_entry; - unsigned long if_send_skb_null; - unsigned long if_send_broadcast; - unsigned long if_send_multicast; - unsigned long if_send_critical_ISR; - unsigned long if_send_critical_non_ISR; - unsigned long if_send_busy; - unsigned long if_send_busy_timeout; - unsigned long if_send_DRVSTATS_request; - unsigned long if_send_PTPIPE_request; - unsigned long if_send_wan_disconnected; - unsigned long if_send_adptr_bfrs_full; - unsigned long if_send_protocol_error; - unsigned long if_send_tx_int_enabled; - unsigned long if_send_bfr_passed_to_adptr; - unsigned long rx_intr_no_socket; - unsigned long rx_intr_DRVSTATS_request; - unsigned long rx_intr_PTPIPE_request; - unsigned long rx_intr_bfr_not_passed_to_stack; - unsigned long rx_intr_bfr_passed_to_stack; - unsigned long UDP_PTPIPE_mgmt_kmalloc_err; - unsigned long UDP_PTPIPE_mgmt_adptr_type_err; - unsigned long UDP_PTPIPE_mgmt_direction_err; - unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_timeout; - unsigned long UDP_PTPIPE_mgmt_adptr_cmnd_OK; - unsigned long UDP_PTPIPE_mgmt_passed_to_adptr; - unsigned long UDP_PTPIPE_mgmt_passed_to_stack; - unsigned long UDP_PTPIPE_mgmt_no_socket; - unsigned long UDP_DRVSTATS_mgmt_kmalloc_err; - unsigned long UDP_DRVSTATS_mgmt_adptr_type_err; - unsigned long UDP_DRVSTATS_mgmt_direction_err; - unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - unsigned long UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - unsigned long UDP_DRVSTATS_mgmt_passed_to_adptr; - unsigned long UDP_DRVSTATS_mgmt_passed_to_stack; - unsigned long UDP_DRVSTATS_mgmt_no_socket; - unsigned long router_up_time; -} ppp_private_area_t; -/* variable for keeping track of enabling/disabling FT1 monitor status */ + if_send_stat_t if_send_stat; + rx_intr_stat_t rx_intr_stat; + pipe_mgmt_stat_t pipe_mgmt_stat; + unsigned long router_up_time; + +}ppp_private_area_t; + +/* variable for keeping track of enabling/disabling FT1 monitor status */ static int rCount = 0; + extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ -static int update(wan_device_t * wandev); -static int new_if(wan_device_t * wandev, struct net_device *dev, - wanif_conf_t * conf); -static int del_if(wan_device_t * wandev, struct net_device *dev); +static int update(wan_device_t *wandev); +static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf); +static int del_if(wan_device_t *wandev, struct net_device *dev); + /* WANPIPE-specific entry points */ -static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data); +static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data); + /* Network device interface */ static int if_init(struct net_device *dev); static int if_open(struct net_device *dev); static int if_close(struct net_device *dev); -static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len); +static int if_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, + void *daddr, void *saddr, unsigned len); static int if_rebuild_hdr(struct sk_buff *skb); +static struct net_device_stats *if_stats(struct net_device *dev); static int if_send(struct sk_buff *skb, struct net_device *dev); -static struct enet_statistics *if_stats(struct net_device *dev); + + /* PPP firmware interface functions */ -static int ppp_read_version(sdla_t * card, char *str); -static int ppp_configure(sdla_t * card, void *data); -static int ppp_set_intr_mode(sdla_t * card, unsigned mode); -static int ppp_comm_enable(sdla_t * card); -static int ppp_comm_disable(sdla_t * card); -static int ppp_get_err_stats(sdla_t * card); -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto); -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb); -/* Interrupt handlers */ -STATIC void wpp_isr(sdla_t * card); -static void rx_intr(sdla_t * card); -static void tx_intr(sdla_t * card); +static int ppp_read_version(sdla_t *card, char *str); +static int ppp_set_outbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); +static int ppp_set_inbnd_auth(sdla_t *card, ppp_private_area_t *ppp_priv_area); +static int ppp_configure(sdla_t *card, void *data); +static int ppp_set_intr_mode(sdla_t *card, unsigned char mode); +static int ppp_comm_enable(sdla_t *card); +static int ppp_comm_disable(sdla_t *card); +static int ppp_get_err_stats(sdla_t *card); +static int ppp_send(sdla_t *card, void *data, unsigned len, unsigned proto); +static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb); + +STATIC void wpp_isr(sdla_t *card); +static void rx_intr(sdla_t *card); +static void event_intr(sdla_t *card); +static void timer_intr(sdla_t *card); + /* Background polling routines */ -static void wpp_poll(sdla_t * card); -static void poll_active(sdla_t * card); -static void poll_connecting(sdla_t * card); -static void poll_disconnected(sdla_t * card); +static void process_route(sdla_t *card); +static void poll_disconnected(sdla_t *card); + /* Miscellaneous functions */ -static int config502(sdla_t * card); -static int config508(sdla_t * card); +static int read_info( sdla_t *card ); +static int read_connection_info (sdla_t *card); +static int remove_route( sdla_t *card ); +static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card); static void show_disc_cause(sdla_t * card, unsigned cause); -static unsigned char bps_to_speed_code(unsigned long bps); -static int reply_udp(unsigned char *data, unsigned int mbox_len); -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area); -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area); -static void init_ppp_tx_rx_buff(sdla_t * card); -static int intr_test(sdla_t * card); -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card); -static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area); -static void init_global_statistics(sdla_t * card); +static int reply_udp( unsigned char *data, unsigned int mbox_len ); +static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, + ppp_private_area_t *ppp_priv_area); +static void init_ppp_tx_rx_buff( sdla_t *card ); +static int intr_test( sdla_t *card ); +static int udp_pkt_type( struct sk_buff *skb , sdla_t *card); +static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area); +static void init_global_statistics( sdla_t *card ); +static int tokenize(char *str, char **tokens); +static char* strstrip(char *str, char *s); +static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev, + struct sk_buff *skb); +static int Read_connection_info; static int Intr_test_counter; -static char TracingEnabled; -static unsigned long curr_trace_addr; -static unsigned long start_trace_addr; static unsigned short available_buffer_space; + /* IPX functions */ -static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming); -static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto); +static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, + unsigned char incoming); +static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_PX, + unsigned long network_number, unsigned short proto); + +/* Lock Functions */ +static void s508_lock (sdla_t *card, unsigned long *smp_flags); +static void s508_unlock (sdla_t *card, unsigned long *smp_flags); + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, struct net_device* dev, + ppp_private_area_t* ppp_priv_area ); +static unsigned short calc_checksum (char *data, int len); + + + /****** Public Functions ****************************************************/ @@ -215,30 +292,40 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char * Return: 0 o.k. * < 0 failure. */ -int wpp_init(sdla_t * card, wandev_conf_t * conf) +int wpp_init(sdla_t *card, wandev_conf_t *conf) { - union { + union + { char str[80]; } u; + /* Verify configuration ID */ if (conf->config_id != WANCONFIG_PPP) { + printk(KERN_INFO "%s: invalid configuration ID %u!\n", - card->devname, conf->config_id); + card->devname, conf->config_id); return -EINVAL; + } - /* Initialize protocol-specific fields */ - switch (card->hw.fwid) { - case SFID_PPP502: - card->mbox = (void *) (card->hw.dpmbase + PPP502_MB_OFFS); - card->flags = (void *) (card->hw.dpmbase + PPP502_FLG_OFFS); - break; - case SFID_PPP508: - card->mbox = (void *) (card->hw.dpmbase + PPP508_MB_OFFS); - card->flags = (void *) (card->hw.dpmbase + PPP508_FLG_OFFS); - break; - default: - return -EINVAL; + + /* Initialize miscellaneous pointers to structures on the adapter */ + switch (card->hw.type) { + + case SDLA_S508: + card->mbox =(void*)(card->hw.dpmbase + PPP508_MB_OFFS); + card->flags=(void*)(card->hw.dpmbase + PPP508_FLG_OFFS); + break; + + case SDLA_S514: + card->mbox =(void*)(card->hw.dpmbase + PPP514_MB_OFFS); + card->flags=(void*)(card->hw.dpmbase + PPP514_FLG_OFFS); + break; + + default: + return -EINVAL; + } + /* Read firmware version. Note that when adapter initializes, it * clears the mailbox, so it may appear that the first command was * executed successfully when in fact it was merely erased. To work @@ -246,33 +333,36 @@ int wpp_init(sdla_t * card, wandev_conf_t * conf) */ if (ppp_read_version(card, NULL) || ppp_read_version(card, u.str)) return -EIO; - printk(KERN_INFO "%s: running PPP firmware v%s\n", card->devname, u.str); + + printk(KERN_INFO "%s: running PPP firmware v%s\n",card->devname, u.str); /* Adjust configuration and set defaults */ card->wandev.mtu = (conf->mtu) ? - min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; - card->wandev.bps = conf->bps; - card->wandev.interface = conf->interface; - card->wandev.clocking = conf->clocking; - card->wandev.station = conf->station; - card->isr = &wpp_isr; - card->poll = &wpp_poll; - card->exec = &wpp_exec; - card->wandev.update = &update; - card->wandev.new_if = &new_if; - card->wandev.del_if = &del_if; - card->wandev.state = WAN_DISCONNECTED; - card->wandev.udp_port = conf->udp_port; - card->wandev.ttl = conf->ttl; + min(conf->mtu, PPP_MAX_MTU) : PPP_DFLT_MTU; + + card->wandev.bps = conf->bps; + card->wandev.interface = conf->interface; + card->wandev.clocking = conf->clocking; + card->wandev.station = conf->station; + card->isr = &wpp_isr; + card->poll = NULL; + card->exec = &wpp_exec; + card->wandev.update = &update; + card->wandev.new_if = &new_if; + card->wandev.del_if = &del_if; + card->wandev.state = WAN_DISCONNECTED; + card->wandev.udp_port = conf->udp_port; + card->wandev.ttl = conf->ttl; card->irq_dis_if_send_count = 0; - card->irq_dis_poll_count = 0; - TracingEnabled = 0; - card->wandev.enable_IPX = conf->enable_IPX; - if (conf->network_number) - card->wandev.network_number = conf->network_number; - else - card->wandev.network_number = 0xDEADBEEF; + card->irq_dis_poll_count = 0; + card->u.p.authenticator = conf->u.ppp.authenticator; + card->u.p.ip_mode = conf->u.ppp.ip_mode ? + conf->u.ppp.ip_mode : WANOPT_PPP_STATIC; + card->TracingEnabled = 0; + Read_connection_info = 1; + /* initialize global statistics */ - init_global_statistics(card); + init_global_statistics( card ); + return 0; } @@ -281,19 +371,43 @@ int wpp_init(sdla_t * card, wandev_conf_t * conf) /*============================================================================ * Update device status & statistics. */ -static int update(wan_device_t * wandev) +static int update(wan_device_t *wandev) { - sdla_t *card; + sdla_t* card = wandev->private; + struct net_device* dev = card->wandev.dev; + volatile ppp_private_area_t *ppp_priv_area = dev->priv; + ppp_flags_t *flags = card->flags; + unsigned long timeout; + /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) return -EFAULT; + if (wandev->state == WAN_UNCONFIGURED) return -ENODEV; - if (test_and_set_bit(0, (void *) &wandev->critical)) + + //FIXME: Do we need this + if (test_bit(0, (void*)&wandev->critical)) return -EAGAIN; - card = wandev->private; - ppp_get_err_stats(card); - wandev->critical = 0; + + ppp_priv_area->update_comms_stats = 2; + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE; + flags->imask |= PPP_INTR_TIMER; + + /* wait a maximum of 1 second for the statistics to be updated */ + timeout = jiffies; + for(;;) { + if(ppp_priv_area->update_comms_stats == 0){ + break; + } + if ((jiffies - timeout) > (1 * HZ)){ + ppp_priv_area->update_comms_stats = 0; + ppp_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + return -EAGAIN; + } + } + return 0; } @@ -309,46 +423,98 @@ static int update(wan_device_t * wandev) * Return: 0 o.k. * < 0 failure (channel will not be created) */ - -static int new_if(wan_device_t * wandev, struct net_device *dev, wanif_conf_t * conf) +static int new_if(wan_device_t *wandev, struct net_device *dev, wanif_conf_t *conf) { sdla_t *card = wandev->private; ppp_private_area_t *ppp_priv_area; + if (wandev->ndev) return -EEXIST; + if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) { + printk(KERN_INFO "%s: invalid interface name!\n", - card->devname); + card->devname); return -EINVAL; + } + /* allocate and initialize private data */ ppp_priv_area = kmalloc(sizeof(ppp_private_area_t), GFP_KERNEL); - if (ppp_priv_area == NULL) - return -ENOMEM; + + if( ppp_priv_area == NULL ) + return -ENOMEM; + memset(ppp_priv_area, 0, sizeof(ppp_private_area_t)); - ppp_priv_area->card = card; + + ppp_priv_area->card = card; + /* initialize data */ strcpy(card->u.p.if_name, conf->name); + /* initialize data in ppp_private_area structure */ - init_ppp_priv_struct(ppp_priv_area); + + init_ppp_priv_struct( ppp_priv_area ); + ppp_priv_area->mc = conf->mc; + ppp_priv_area->pap = conf->pap; + ppp_priv_area->chap = conf->chap; + + /* If no user ids are specified */ + if(!strlen(conf->userid) && (ppp_priv_area->pap||ppp_priv_area->chap)){ + kfree(ppp_priv_area); + return -EINVAL; + } + + /* If no passwords are specified */ + if(!strlen(conf->passwd) && (ppp_priv_area->pap||ppp_priv_area->chap)){ + kfree(ppp_priv_area); + return -EINVAL; + } + + if(strlen(conf->sysname) > 31){ + kfree(ppp_priv_area); + return -EINVAL; + } + + /* If no system name is specified */ + if(!strlen(conf->sysname) && (card->u.p.authenticator)){ + kfree(ppp_priv_area); + return -EINVAL; + } + + /* copy the data into the ppp private structure */ + memcpy(ppp_priv_area->userid, conf->userid, strlen(conf->userid)); + memcpy(ppp_priv_area->passwd, conf->passwd, strlen(conf->passwd)); + memcpy(ppp_priv_area->sysname, conf->sysname, strlen(conf->sysname)); + + + ppp_priv_area->enable_IPX = conf->enable_IPX; + if (conf->network_number) + ppp_priv_area->network_number = conf->network_number; + else + ppp_priv_area->network_number = 0xDEADBEEF; + + /* prepare network device data space for registration */ dev->name = card->u.p.if_name; dev->init = &if_init; dev->priv = ppp_priv_area; + return 0; } /*============================================================================ * Delete logical channel. */ - -static int del_if(wan_device_t * wandev, struct net_device *dev) +static int del_if(wan_device_t *wandev, struct net_device *dev) { if (dev->priv) { - kfree(dev->priv); - dev->priv = NULL; - } + + kfree(dev->priv); + dev->priv = NULL; + } + return 0; } @@ -358,26 +524,36 @@ static int del_if(wan_device_t * wandev, struct net_device *dev) * Execute adapter interface command. */ +//FIXME: Why do we need this ???? static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) { ppp_mbox_t *mbox = card->mbox; int len; - if(copy_from_user((void *) &mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) + + if (copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) return -EFAULT; + len = mbox->cmd.length; + if (len) { - if(copy_from_user((void *) &mbox->data, u_data, len)) + + if( copy_from_user((void*)&mbox->data, u_data, len)) return -EFAULT; + } + /* execute command */ if (!sdla_exec(mbox)) return -EIO; + /* return result */ - if(copy_to_user(u_cmd, (void *) &mbox->cmd, sizeof(ppp_cmd_t))) + if( copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t))) return -EFAULT; len = mbox->cmd.length; - if (len && u_data && copy_to_user(u_data, (void *) &mbox->data, len)) + + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) return -EFAULT; + return 0; } @@ -390,32 +566,49 @@ static int wpp_exec(struct sdla *card, void *u_cmd, void *u_data) * interface registration. Returning anything but zero will fail interface * registration. */ - static int if_init(struct net_device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; wan_device_t *wandev = &card->wandev; +#ifndef LINUX_2_1 + int i; +#endif /* Initialize device driver entry points */ - dev->open = &if_open; - dev->stop = &if_close; - dev->hard_header = &if_header; - dev->rebuild_header = &if_rebuild_hdr; - dev->hard_start_xmit = &if_send; - dev->get_stats = &if_stats; + dev->open = &if_open; + dev->stop = &if_close; + dev->hard_header = &if_header; + dev->rebuild_header = &if_rebuild_hdr; + dev->hard_start_xmit = &if_send; + dev->get_stats = &if_stats; + + /* Initialize media-specific parameters */ - dev->type = ARPHRD_PPP; /* ARP h/w type */ - dev->mtu = wandev->mtu; - dev->hard_header_len = PPP_HDR_LEN; /* media header length */ + dev->type = ARPHRD_PPP; /* ARP h/w type */ + dev->flags |= IFF_POINTOPOINT; + + /* Enable Mulitcasting if specified by user*/ + if (ppp_priv_area->mc == WANOPT_YES){ + dev->flags |= IFF_MULTICAST; + } + +#ifndef LINUX_2_1 + dev->family = AF_INET; +#endif + dev->mtu = wandev->mtu; + dev->hard_header_len = PPP_HDR_LEN; /* media header length */ + /* Initialize hardware parameters (just for reference) */ - dev->irq = wandev->irq; - dev->dma = wandev->dma; - dev->base_addr = wandev->ioport; - dev->mem_start = (unsigned long)wandev->maddr; - dev->mem_end = dev->mem_start + wandev->msize - 1; - /* Set transmit buffer queue length */ - dev->tx_queue_len = 100; + dev->irq = wandev->irq; + dev->dma = wandev->dma; + dev->base_addr = wandev->ioport; + dev->mem_start = wandev->maddr; + dev->mem_end = wandev->maddr + wandev->msize - 1; + + /* Set transmit buffer queue length */ + dev->tx_queue_len = 100; + /* Initialize socket buffers */ dev_init_buffers(dev); return 0; @@ -428,7 +621,6 @@ static int if_init(struct net_device *dev) * * Return 0 if O.k. or errno. */ - static int if_open(struct net_device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; @@ -436,48 +628,100 @@ static int if_open(struct net_device *dev) ppp_flags_t *flags = card->flags; struct timeval tv; int err = 0; + if (dev->start) - return -EBUSY; /* only one open is allowed */ - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + return -EBUSY; /* only one open is allowed */ + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; - if ((card->hw.fwid == SFID_PPP502) ? config502(card) : config508(card)) { - err = -EIO; - card->wandev.critical = 0; - return err; - } - Intr_test_counter = 0; - err = intr_test(card); - if ((err) || (Intr_test_counter != (MAX_INTR_TEST_COUNTER + 1))) { - printk(KERN_INFO "%s: Interrupt Test Failed, Counter: %i\n", - card->devname, Intr_test_counter); - err = -EIO; - card->wandev.critical = 0; - return err; + + if (!card->configured){ + + if (config508(ppp_priv_area, card)){ + + err = -EIO; + card->wandev.critical = 0; + return err; + } + + Intr_test_counter = 0; + err = intr_test( card ); + + if(err || (Intr_test_counter < MAX_INTR_TEST_COUNTER)) { + printk("%s: Interrupt Test Failed, Counter: %i\n", + card->devname, Intr_test_counter); + printk( "%s: Please choose another interrupt\n",card->devname); + err = -EIO; + card->wandev.critical = 0; + return err; + } + + printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", + card->devname, Intr_test_counter); + card->configured = 1; + } - printk(KERN_INFO "%s: Interrupt Test Passed, Counter: %i\n", - card->devname, Intr_test_counter); + /* Initialize Rx/Tx buffer control fields */ - init_ppp_tx_rx_buff(card); - if (ppp_set_intr_mode(card, 0x03)) { + init_ppp_tx_rx_buff( card ); + + if (ppp_set_intr_mode(card, PPP_INTR_RXRDY| + PPP_INTR_TXRDY| + PPP_INTR_MODEM| + PPP_INTR_CMD | + PPP_INTR_DISC | + PPP_INTR_OPEN | + PPP_INTR_DROP_DTR | + PPP_INTR_TIMER)) { + err = -EIO; card->wandev.critical = 0; return err; + } - flags->imask &= ~0x02; + + /* Turn off the transmit and timer interrupt */ + flags->imask &= ~(PPP_INTR_TXRDY | PPP_INTR_TIMER) ; + + /* If you are not the authenticator and any one of the protocol is + * enabled then we call the set_out_bound_authentication. + */ + if ( !card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_outbnd_auth(card, ppp_priv_area) ){ + err = -EIO; + card->wandev.critical = 0; + return err; + } + } + + /* If you are the authenticator and any one of the protocol is enabled + * then we call the set_in_bound_authentication. + */ + if ( card->u.p.authenticator && (ppp_priv_area->pap || ppp_priv_area->chap)) { + if ( ppp_set_inbnd_auth(card, ppp_priv_area) ){ + err = -EIO; + card->wandev.critical = 0; + return err; + } + } + if (ppp_comm_enable(card)) { err = -EIO; card->wandev.critical = 0; return err; } + + wanpipe_set_state(card, WAN_CONNECTING); wanpipe_open(card); dev->mtu = min(dev->mtu, card->wandev.mtu); dev->interrupt = 0; dev->tbusy = 0; dev->start = 1; - do_gettimeofday(&tv); + do_gettimeofday( &tv ); ppp_priv_area->router_start_time = tv.tv_sec; card->wandev.critical = 0; + return err; } @@ -486,13 +730,14 @@ static int if_open(struct net_device *dev) * o if this is the last open, then disable communications and interrupts. * o reset flags. */ - static int if_close(struct net_device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) return -EAGAIN; + dev->start = 0; wanpipe_close(card); wanpipe_set_state(card, WAN_DISCONNECTED); @@ -511,19 +756,21 @@ static int if_close(struct net_device *dev) * * Return: media header length. */ - static int if_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) + unsigned short type, void *daddr, void *saddr, unsigned len) { - switch (type) + switch (type) { case ETH_P_IP: + case ETH_P_IPX: - skb->protocol = type; + skb->protocol = htons(type); break; + default: skb->protocol = 0; } + return PPP_HDR_LEN; } @@ -534,13 +781,14 @@ static int if_header(struct sk_buff *skb, struct net_device *dev, * 0 physical address not resolved */ -static int if_rebuild_hdr(struct sk_buff *skb) +static int if_rebuild_hdr (struct sk_buff *skb) { - struct net_device *dev=skb->dev; + struct net_device *dev = skb->dev; ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; + printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name); + card->devname, dev->name); return 1; } @@ -561,303 +809,355 @@ static int if_rebuild_hdr(struct sk_buff *skb) * 2. Setting tbusy flag will inhibit further transmit requests from the * protocol stack and can be used for flow control with protocol layer. */ - -static int if_send(struct sk_buff *skb, struct net_device *dev) +static int if_send (struct sk_buff *skb, struct net_device *dev) { ppp_private_area_t *ppp_priv_area = dev->priv; sdla_t *card = ppp_priv_area->card; unsigned char *sendpacket; - unsigned long check_braddr, check_mcaddr; - unsigned long host_cpu_flags; + unsigned long smp_flags; ppp_flags_t *flags = card->flags; int retry = 0; - int err, udp_type; - ++ppp_priv_area->if_send_entry; + int udp_type; + + + ++ppp_priv_area->if_send_stat.if_send_entry; + if (skb == NULL) { + /* If we get here, some higher layer thinks we've missed an * tx-done interrupt. */ printk(KERN_INFO "%s: interface %s got kicked!\n", - card->devname, dev->name); - ++ppp_priv_area->if_send_skb_null; + card->devname, dev->name); + + ++ppp_priv_area->if_send_stat.if_send_skb_null; + mark_bh(NET_BH); return 0; + } + if (dev->tbusy) { + /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. */ - ++ppp_priv_area->if_send_busy; - ++card->wandev.stats.collisions; - if ((jiffies - ppp_priv_area->tick_counter) < (5 * HZ)) { + + ++ppp_priv_area->if_send_stat.if_send_tbusy; + ++card->wandev.stats.collisions; + + if ((jiffies - ppp_priv_area->tick_counter) < (5*HZ)) { return 1; } - printk(KERN_INFO "%s: Transmit times out\n", card->devname); - ++ppp_priv_area->if_send_busy_timeout; - /* unbusy the card (because only one interface per card) */ + + printk (KERN_INFO "%s: Transmit times out\n",card->devname); + + ++ppp_priv_area->if_send_stat.if_send_tbusy_timeout; + ++card->wandev.stats.collisions; + + /* unbusy the card (because only one interface per card)*/ dev->tbusy = 0; - } + } sendpacket = skb->data; - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) { - ++ppp_priv_area->if_send_DRVSTATS_request; - process_udp_driver_call(UDP_PKT_FRM_STACK, card, skb, dev, - ppp_priv_area); - dev_kfree_skb(skb); - return 0; - } else if (udp_type == UDP_PTPIPE_TYPE) - ++ppp_priv_area->if_send_PTPIPE_request; - /* retreive source address in two forms: broadcast & multicast */ - check_braddr = sendpacket[15]; - check_mcaddr = sendpacket[12]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[14]; - check_mcaddr |= sendpacket[13]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[13]; - check_mcaddr |= sendpacket[14]; - check_braddr = check_braddr << 8; - check_mcaddr = check_mcaddr << 8; - check_braddr |= sendpacket[12]; - check_mcaddr |= sendpacket[15]; - /* if the Source Address is a Multicast address */ - if ((ppp_priv_area->mc == WANOPT_NO) && (check_mcaddr >= 0xE0000001) - && (check_mcaddr <= 0xFFFFFFFE)) { - printk(KERN_INFO "%s: Mutlicast Src. Addr. silently discarded\n" - ,card->devname); - dev_kfree_skb(skb); - ++ppp_priv_area->if_send_multicast; - ++card->wandev.stats.tx_dropped; + + udp_type = udp_pkt_type( skb, card ); + + + if (udp_type == UDP_PTPIPE_TYPE){ + if(store_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, dev, + ppp_priv_area)){ + flags->imask |= PPP_INTR_TIMER; + } + ++ppp_priv_area->if_send_stat.if_send_PIPE_request; return 0; + } - disable_irq(card->hw.irq); - ++card->irq_dis_if_send_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { - if (card->wandev.critical == CRITICAL_IN_ISR) { - /* If the critical flag is set due to an Interrupt - * then set enable transmit interrupt flag to enable - * transmit interrupt. (delay interrupt) - */ - card->wandev.enable_tx_int = 1; - dev->tbusy = 1; - /* set the counter to see if we get the interrupt in - * 5 seconds. - */ - ppp_priv_area->tick_counter = jiffies; - ++ppp_priv_area->if_send_critical_ISR; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return 1; + + /* Check for broadcast and multicast addresses + * If found, drop (deallocate) a packet and return. + */ + if(chk_bcast_mcast_addr(card, dev, skb)){ + return 0; + } + + + if(card->hw.type != SDLA_S514){ + s508_lock(card,&smp_flags); + } + + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + printk(KERN_INFO "%s: Critical in if_send: %x\n", + card->wandev.name,card->wandev.critical); + dev_kfree_skb(skb); + + ++card->wandev.stats.tx_dropped; + ++ppp_priv_area->if_send_stat.if_send_critical_non_ISR; + + if(card->hw.type != SDLA_S514){ + s508_unlock(card,&smp_flags); } - dev_kfree_skb(skb); - ++ppp_priv_area->if_send_critical_non_ISR; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && - (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + return 0; } - if (udp_type == UDP_PTPIPE_TYPE) { - err = process_udp_mgmt_pkt(UDP_PKT_FRM_STACK, card, skb, - dev, ppp_priv_area); - } else if (card->wandev.state != WAN_CONNECTED) { - ++ppp_priv_area->if_send_wan_disconnected; - ++card->wandev.stats.tx_dropped; - } else if (!skb->protocol) { - ++ppp_priv_area->if_send_protocol_error; - ++card->wandev.stats.tx_errors; + + if (card->wandev.state != WAN_CONNECTED) { + + ++ppp_priv_area->if_send_stat.if_send_wan_disconnected; + ++card->wandev.stats.tx_dropped; + + } else if (!skb->protocol) { + ++ppp_priv_area->if_send_stat.if_send_protocol_error; + ++card->wandev.stats.tx_errors; + } else { - /*If it's IPX change the network numbers to 0 if they're ours. */ - if (skb->protocol == ETH_P_IPX) { - if (card->wandev.enable_IPX) { - switch_net_numbers(skb->data, - card->wandev.network_number, 0); + + /*If it's IPX change the network numbers to 0 if they're ours.*/ + if( skb->protocol == htons(ETH_P_IPX) ) { + if(ppp_priv_area->enable_IPX) { + switch_net_numbers( skb->data, + ppp_priv_area->network_number, 0); } else { ++card->wandev.stats.tx_dropped; goto tx_done; } } + if (ppp_send(card, skb->data, skb->len, skb->protocol)) { retry = 1; dev->tbusy = 1; - ++ppp_priv_area->if_send_adptr_bfrs_full; - ++ppp_priv_area->if_send_tx_int_enabled; + ++ppp_priv_area->if_send_stat.if_send_adptr_bfrs_full; + ++ppp_priv_area->if_send_stat.if_send_tx_int_enabled; ppp_priv_area->tick_counter = jiffies; - ++card->wandev.stats.tx_errors; flags->imask |= 0x02; /* unmask Tx interrupts */ } else { - ++ppp_priv_area->if_send_bfr_passed_to_adptr; + ++ppp_priv_area->if_send_stat.if_send_bfr_passed_to_adptr; ++card->wandev.stats.tx_packets; card->wandev.stats.tx_bytes += skb->len; } - } -tx_done: - if (!retry) { + } + +tx_done: + if (!retry){ dev_kfree_skb(skb); } + card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!(--card->irq_dis_if_send_count)) && (!card->irq_dis_poll_count)) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); + + if(card->hw.type != SDLA_S514){ + s508_unlock(card,&smp_flags); + } + + return retry; } + +/*============================================================================= + * Store a UDP management packet for later processing. + */ + +static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card, + struct sk_buff *skb, struct net_device* dev, + ppp_private_area_t* ppp_priv_area ) +{ + int udp_pkt_stored = 0; + + if(!ppp_priv_area->udp_pkt_lgth && (skb->len<=MAX_LGTH_UDP_MGNT_PKT)){ + ppp_priv_area->udp_pkt_lgth = skb->len; + ppp_priv_area->udp_pkt_src = udp_pkt_src; + memcpy(ppp_priv_area->udp_pkt_data, skb->data, skb->len); + ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UDP; + ppp_priv_area->protocol = skb->protocol; + udp_pkt_stored = 1; + }else{ + if (skb->len > MAX_LGTH_UDP_MGNT_PKT){ + printk(KERN_INFO "%s: PIPEMON UDP request too long : %i\n", + card->devname, skb->len); + }else{ + printk(KERN_INFO "%s: PIPEMON UPD request already pending\n", + card->devname); + } + ppp_priv_area->udp_pkt_lgth = 0; + } + + dev_kfree_skb(skb); + return(udp_pkt_stored); +} + + + /*============================================================================ * Reply to UDP Management system. * Return length of reply. */ - -static int reply_udp(unsigned char *data, unsigned int mbox_len) +static int reply_udp( unsigned char *data, unsigned int mbox_len ) { - unsigned short len, udp_length, temp, i, ip_length; - unsigned long sum; + unsigned short len, udp_length, temp, ip_length; + unsigned long ip_temp; + int even_bound = 0; + ppp_udp_pkt_t *p_udp_pkt = (ppp_udp_pkt_t *)data; + /* Set length of packet */ - len = mbox_len + 60; + len = sizeof(ip_pkt_t)+ + sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + mbox_len; + /* fill in UDP reply */ - data[36] = 0x02; + p_udp_pkt->wp_mgmt.request_reply = UDPMGMT_REPLY; + /* fill in UDP length */ - udp_length = mbox_len + 40; + udp_length = sizeof(udp_pkt_t)+ + sizeof(wp_mgmt_t)+ + sizeof(cblock_t)+ + mbox_len; + + /* put it on an even boundary */ - if (udp_length & 0x0001) { + if ( udp_length & 0x0001 ) { udp_length += 1; len += 1; - } - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[24], &temp, 2); + even_bound=1; + } + + temp = (udp_length<<8)|(udp_length>>8); + p_udp_pkt->udp_pkt.udp_length = temp; + + /* swap UDP ports */ - memcpy(&temp, &data[20], 2); - memcpy(&data[20], &data[22], 2); - memcpy(&data[22], &temp, 2); + temp = p_udp_pkt->udp_pkt.udp_src_port; + p_udp_pkt->udp_pkt.udp_src_port = + p_udp_pkt->udp_pkt.udp_dst_port; + p_udp_pkt->udp_pkt.udp_dst_port = temp; + + /* add UDP pseudo header */ temp = 0x1100; - memcpy(&data[udp_length + 20], &temp, 2); - temp = (udp_length << 8) | (udp_length >> 8); - memcpy(&data[udp_length + 22], &temp, 2); + *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound)) = temp; + temp = (udp_length<<8)|(udp_length>>8); + *((unsigned short *)(p_udp_pkt->data+mbox_len+even_bound+2)) = temp; + /* calculate UDP checksum */ - data[26] = data[27] = 0; - sum = 0; - for (i = 0; i < udp_length + 12; i += 2) { - memcpy(&temp, &data[12 + i], 2); - sum += (unsigned long) temp; - } - while (sum >> 16) { - sum = (sum & 0xffffUL) + (sum >> 16); - } - temp = (unsigned short) sum; - temp = ~temp; - if (temp == 0) - temp = 0xffff; - memcpy(&data[26], &temp, 2); + p_udp_pkt->udp_pkt.udp_checksum = 0; + p_udp_pkt->udp_pkt.udp_checksum = + calc_checksum(&data[UDP_OFFSET],udp_length+UDP_OFFSET); + /* fill in IP length */ - ip_length = udp_length + 20; - temp = (ip_length << 8) | (ip_length >> 8); - memcpy(&data[2], &temp, 2); + ip_length = udp_length + sizeof(ip_pkt_t); + temp = (ip_length<<8)|(ip_length>>8); + p_udp_pkt->ip_pkt.total_length = temp; + /* swap IP addresses */ - memcpy(&temp, &data[12], 2); - memcpy(&data[12], &data[16], 2); - memcpy(&data[16], &temp, 2); - memcpy(&temp, &data[14], 2); - memcpy(&data[14], &data[18], 2); - memcpy(&data[18], &temp, 2); + ip_temp = p_udp_pkt->ip_pkt.ip_src_address; + p_udp_pkt->ip_pkt.ip_src_address = p_udp_pkt->ip_pkt.ip_dst_address; + p_udp_pkt->ip_pkt.ip_dst_address = ip_temp; + /* fill in IP checksum */ - data[10] = data[11] = 0; - sum = 0; - for (i = 0; i < 20; i += 2) { - memcpy(&temp, &data[i], 2); - sum += (unsigned long) temp; + p_udp_pkt->ip_pkt.hdr_checksum = 0; + p_udp_pkt->ip_pkt.hdr_checksum = calc_checksum(data,sizeof(ip_pkt_t)); + + return len; + +} /* reply_udp */ + +unsigned short calc_checksum (char *data, int len) +{ + unsigned short temp; + unsigned long sum=0; + int i; + + for( i = 0; i <len; i+=2 ) { + memcpy(&temp,&data[i],2); + sum += (unsigned long)temp; } - while (sum >> 16) { + + while (sum >> 16 ) { sum = (sum & 0xffffUL) + (sum >> 16); } - temp = (unsigned short) sum; + + temp = (unsigned short)sum; temp = ~temp; - if (temp == 0) + + if( temp == 0 ) temp = 0xffff; - memcpy(&data[10], &temp, 2); - return len; -} /* reply_udp */ + + return temp; +} /* If incoming is 0 (outgoing)- if the net numbers is ours make it 0 if incoming is 1 - if the net number is 0 make it ours - */ +*/ static void switch_net_numbers(unsigned char *sendpacket, unsigned long network_number, unsigned char incoming) { unsigned long pnetwork_number; - pnetwork_number = (unsigned long) ((sendpacket[6] << 24) + - (sendpacket[7] << 16) + (sendpacket[8] << 8) + - sendpacket[9]); + + pnetwork_number = (unsigned long)((sendpacket[6] << 24) + + (sendpacket[7] << 16) + (sendpacket[8] << 8) + + sendpacket[9]); + if (!incoming) { - /* If the destination network number is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[6] = sendpacket[7] = sendpacket[8] = - sendpacket[9] = 0x00; + //If the destination network number is ours, make it 0 + if( pnetwork_number == network_number) { + sendpacket[6] = sendpacket[7] = sendpacket[8] = + sendpacket[9] = 0x00; } } else { - /* If the incoming network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[6] = (unsigned char) (network_number >> 24); - sendpacket[7] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[8] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[9] = (unsigned char) (network_number & - 0x000000FF); + //If the incoming network is 0, make it ours + if( pnetwork_number == 0) { + sendpacket[6] = (unsigned char)(network_number >> 24); + sendpacket[7] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[8] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[9] = (unsigned char)(network_number & + 0x000000FF); } } - pnetwork_number = (unsigned long) ((sendpacket[18] << 24) + - (sendpacket[19] << 16) + (sendpacket[20] << 8) + - sendpacket[21]); - if (!incoming) { - /* If the source network is ours, make it 0 */ - if (pnetwork_number == network_number) { - sendpacket[18] = sendpacket[19] = sendpacket[20] = - sendpacket[21] = 0x00; + + + pnetwork_number = (unsigned long)((sendpacket[18] << 24) + + (sendpacket[19] << 16) + (sendpacket[20] << 8) + + sendpacket[21]); + + if( !incoming ) { + //If the source network is ours, make it 0 + if( pnetwork_number == network_number) { + sendpacket[18] = sendpacket[19] = sendpacket[20] = + sendpacket[21] = 0x00; } } else { - /* If the source network is 0, make it ours */ - if (pnetwork_number == 0) { - sendpacket[18] = (unsigned char) (network_number >> 24); - sendpacket[19] = (unsigned char) ((network_number & - 0x00FF0000) >> 16); - sendpacket[20] = (unsigned char) ((network_number & - 0x0000FF00) >> 8); - sendpacket[21] = (unsigned char) (network_number & - 0x000000FF); + //If the source network is 0, make it ours + if( pnetwork_number == 0 ) { + sendpacket[18] = (unsigned char)(network_number >> 24); + sendpacket[19] = (unsigned char)((network_number & + 0x00FF0000) >> 16); + sendpacket[20] = (unsigned char)((network_number & + 0x0000FF00) >> 8); + sendpacket[21] = (unsigned char)(network_number & + 0x000000FF); } } -} /* switch_net_numbers */ +} /* switch_net_numbers */ /*============================================================================ - * Get Ethernet-style interface statistics. - * Return a pointer to struct enet_statistics. + * Get ethernet-style interface statistics. + * Return a pointer to struct net_device_stats. */ - -static struct enet_statistics *if_stats(struct net_device *dev) +static struct net_device_stats *if_stats(struct net_device *dev) { + ppp_private_area_t *ppp_priv_area = dev->priv; - sdla_t *card; + sdla_t* card; - /* - * Device is down:No statistics - */ - - if(ppp_priv_area==NULL) + if( ppp_priv_area == NULL ) return NULL; - + card = ppp_priv_area->card; return &card->wandev.stats; } @@ -868,122 +1168,257 @@ static struct enet_statistics *if_stats(struct net_device *dev) * Read firmware code version. * Put code version as ASCII string in str. */ - -static int ppp_read_version(sdla_t * card, char *str) +static int ppp_read_version(sdla_t *card, char *str) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_READ_CODE_VERSION; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) + ppp_error(card, err, mb); + else if (str) { + int len = mb->cmd.length; + memcpy(str, mb->data, len); str[len] = '\0'; + + } + + return err; +} +/*=========================================================================== + * Set Out-Bound Authentication. +*/ +static int ppp_set_outbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) +{ + ppp_mbox_t *mb = card->mbox; + int err; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + memset(&mb->data, 0, (strlen(ppp_priv_area->userid) + + strlen(ppp_priv_area->passwd) + 2 ) ); + memcpy(mb->data, ppp_priv_area->userid, strlen(ppp_priv_area->userid)); + memcpy((mb->data + strlen(ppp_priv_area->userid) + 1), + ppp_priv_area->passwd, strlen(ppp_priv_area->passwd)); + + mb->cmd.length = strlen(ppp_priv_area->userid) + + strlen(ppp_priv_area->passwd) + 2 ; + + mb->cmd.command = PPP_SET_OUTBOUND_AUTH; + + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) + ppp_error(card, err, mb); + + return err; +} + +/*=========================================================================== + * Set In-Bound Authentication. +*/ +static int ppp_set_inbnd_auth (sdla_t *card, ppp_private_area_t *ppp_priv_area) +{ + ppp_mbox_t *mb = card->mbox; + int err, i; + char* user_tokens[32]; + char* pass_tokens[32]; + int userids, passwds; + int add_ptr; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + memset(&mb->data, 0, 1008); + memcpy(mb->data, ppp_priv_area->sysname, + strlen(ppp_priv_area->sysname)); + + /* Parse the userid string and the password string and build a string + to copy it to the data area of the command structure. The string + will look like "SYS_NAME<NULL>USER1<NULL>PASS1<NULL>USER2<NULL>PASS2 + ....<NULL> " + */ + userids = tokenize( ppp_priv_area->userid, user_tokens); + passwds = tokenize( ppp_priv_area->passwd, pass_tokens); + + if (userids != passwds){ + printk(KERN_INFO "%s: Number of passwords does not equal the number of user ids\n", card->devname); + return 1; } + + add_ptr = strlen(ppp_priv_area->sysname) + 1; + for (i=0; i<userids; i++){ + memcpy((mb->data + add_ptr), user_tokens[i], + strlen(user_tokens[i])); + memcpy((mb->data + add_ptr + strlen(user_tokens[i]) + 1), + pass_tokens[i], strlen(pass_tokens[i])); + add_ptr = add_ptr + strlen(user_tokens[i]) + 1 + + strlen(pass_tokens[i]) + 1; + } + + mb->cmd.length = add_ptr + 1; + mb->cmd.command = PPP_SET_INBOUND_AUTH; + + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) + ppp_error(card, err, mb); + return err; } + /*============================================================================ - * Configure PPP firmware. + * Tokenize string. + * Parse a string of the following syntax: + * <arg1>,<arg2>,... + * and fill array of tokens with pointers to string elements. + * */ +static int tokenize (char *str, char **tokens) +{ + int cnt = 0; + + tokens[0] = strtok(str, "/"); + while (tokens[cnt] && (cnt < 32 - 1)) + { + tokens[cnt] = strstrip(tokens[cnt], " \t"); + tokens[++cnt] = strtok(NULL, "/"); + } + return cnt; +} -static int ppp_configure(sdla_t * card, void *data) +/*============================================================================ + * Strip leading and trailing spaces off the string str. + */ +static char* strstrip (char *str, char* s) +{ + char *eos = str + strlen(str); /* -> end of string */ + + while (*str && strchr(s, *str)) + ++str /* strip leading spaces */ + ; + while ((eos > str) && strchr(s, *(eos - 1))) + --eos /* strip trailing spaces */ + ; + *eos = '\0'; + return str; +} +/*============================================================================ + * Configure PPP firmware. + */ +static int ppp_configure(sdla_t *card, void *data) { ppp_mbox_t *mb = card->mbox; - int data_len = (card->hw.fwid == SFID_PPP502) ? - sizeof(ppp502_conf_t) : sizeof(ppp508_conf_t); + int data_len = sizeof(ppp508_conf_t); int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); memcpy(mb->data, data, data_len); - mb->cmd.length = data_len; + mb->cmd.length = data_len; mb->cmd.command = PPP_SET_CONFIG; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Set interrupt mode. */ - -static int ppp_set_intr_mode(sdla_t * card, unsigned mode) +static int ppp_set_intr_mode(sdla_t *card, unsigned char mode) { ppp_mbox_t *mb = card->mbox; + ppp_intr_info_t *ppp_intr_data = (ppp_intr_info_t *) &mb->data[0]; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->data[0] = mode; - switch (card->hw.fwid) { - case SFID_PPP502: - mb->cmd.length = 1; - break; - case SFID_PPP508: - default: - mb->data[1] = card->hw.irq; - mb->cmd.length = 2; - } + ppp_intr_data->i_enable = mode; + + ppp_intr_data->irq = card->hw.irq; + mb->cmd.length = 2; + + /* If timer has been enabled, set the timer delay to 1sec */ + if (mode & 0x80){ + ppp_intr_data->timer_len = 5;//100; //250; + mb->cmd.length = 4; + } + mb->cmd.command = PPP_SET_INTR_FLAGS; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + + return err; } /*============================================================================ * Enable communications. */ - -static int ppp_comm_enable(sdla_t * card) +static int ppp_comm_enable(sdla_t *card) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_COMM_ENABLE; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Disable communications. */ - -static int ppp_comm_disable(sdla_t * card) +static int ppp_comm_disable(sdla_t *card) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_COMM_DISABLE; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + if (err != CMD_OK) ppp_error(card, err, mb); + return err; } /*============================================================================ * Get communications error statistics. */ - -static int ppp_get_err_stats(sdla_t * card) +static int ppp_get_err_stats(sdla_t *card) { ppp_mbox_t *mb = card->mbox; int err; + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); mb->cmd.command = PPP_READ_ERROR_STATS; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err == CMD_OK) { - ppp_err_stats_t *stats = (void *) mb->data; - card->wandev.stats.rx_over_errors = stats->rx_overrun; - card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; - card->wandev.stats.rx_missed_errors = stats->rx_abort; - card->wandev.stats.rx_length_errors = stats->rx_lost; + + ppp_err_stats_t* stats = (void*)mb->data; + card->wandev.stats.rx_over_errors = stats->rx_overrun; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_abort; + card->wandev.stats.rx_length_errors = stats->rx_lost; card->wandev.stats.tx_aborted_errors = stats->tx_abort; - } else + + } else ppp_error(card, err, mb); + return err; } @@ -992,27 +1427,30 @@ static int ppp_get_err_stats(sdla_t * card) * Return: 0 - o.k. * 1 - no transmit buffers available */ - -static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto) +static int ppp_send (sdla_t *card, void *data, unsigned len, unsigned proto) { ppp_buf_ctl_t *txbuf = card->u.p.txbuf; - unsigned long addr; + if (txbuf->flag) - return 1 - ; - if (card->hw.fwid == SFID_PPP502) - addr = (txbuf->buf.o_p[1] << 8) + txbuf->buf.o_p[0]; - else - addr = txbuf->buf.ptr; - sdla_poke(&card->hw, addr, data, len); - txbuf->length = len; /* frame length */ - if (proto == ETH_P_IPX) + return 1; + + sdla_poke(&card->hw, txbuf->buf.ptr, data, len); + + txbuf->length = len; /* frame length */ + + if (proto == htons(ETH_P_IPX)) txbuf->proto = 0x01; /* protocol ID */ - txbuf->flag = 1; /* start transmission */ + else + txbuf->proto = 0x00; /* protocol ID */ + + txbuf->flag = 1; /* start transmission */ + /* Update transmit buffer control fields */ card->u.p.txbuf = ++txbuf; - if ((void *) txbuf > card->u.p.txbuf_last) + + if ((void*)txbuf > card->u.p.txbuf_last) card->u.p.txbuf = card->u.p.txbuf_base; + return 0; } @@ -1025,19 +1463,22 @@ static int ppp_send(sdla_t * card, void *data, unsigned len, unsigned proto) * * Return zero if previous command has to be cancelled. */ - -static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb) +static int ppp_error(sdla_t *card, int err, ppp_mbox_t *mb) { unsigned cmd = mb->cmd.command; + switch (err) { - case CMD_TIMEOUT: - printk(KERN_ERR "%s: command 0x%02X timed out!\n", - card->devname, cmd); - break; - default: - printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" - ,card->devname, cmd, err); + + case CMD_TIMEOUT: + printk(KERN_ERR "%s: command 0x%02X timed out!\n", + card->devname, cmd); + break; + + default: + printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n" + , card->devname, cmd, err); } + return 0; } @@ -1046,81 +1487,89 @@ static int ppp_error(sdla_t * card, int err, ppp_mbox_t * mb) /*============================================================================ * PPP interrupt service routine. */ - -STATIC void wpp_isr(sdla_t * card) +STATIC void wpp_isr(sdla_t *card) { ppp_flags_t *flags = card->flags; char *ptr = &flags->iflag; - unsigned long host_cpu_flags; struct net_device *dev = card->wandev.dev; + + int i; + card->in_isr = 1; + ++card->statistics.isr_entry; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { - ++card->statistics.isr_already_critical; - printk(KERN_INFO "%s: Critical while in ISR!\n", card->devname); - card->in_isr = 0; - return; + + //FIXME: Do we need this + card->force_enable_irq = 0; + + if(card->hw.type != SDLA_S514){ + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { + + ++card->statistics.isr_already_critical; + printk (KERN_INFO "%s: Critical while in ISR!\n", + card->devname); + card->in_isr = 0; + return; + + } } - /* For all interrupts set the critical flag to CRITICAL_IN_ISR. - * If the if_send routine is called with this flag set it will set - * the enable transmit flag to 1. (for a delayed interrupt) - */ - card->wandev.critical = CRITICAL_IN_ISR; + card->buff_int_mode_unbusy = 0; + switch (flags->iflag) { - case 0x01: /* receive interrupt */ - ++card->statistics.isr_rx; - rx_intr(card); - break; - case 0x02: /* transmit interrupt */ - ++card->statistics.isr_tx; - flags->imask &= ~0x02; - dev->tbusy = 0; - card->buff_int_mode_unbusy = 1; - break; - case 0x08: - ++Intr_test_counter; - ++card->statistics.isr_intr_test; - break; - default: /* unexpected interrupt */ - ++card->statistics.isr_spurious; - printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", - card->devname, flags->iflag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) - printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); - } - /* The critical flag is set to CRITICAL_INTR_HANDLED to let the - * if_send call know that the interrupt is handled so that - * transmit interrupts are not enabled again. - */ - card->wandev.critical = CRITICAL_INTR_HANDLED; - /* If the enable transmit interrupt flag is set then enable transmit - * interrupt on the board. This only goes through if if_send is called - * and the critical flag is set due to an Interrupt. - */ - if (card->wandev.enable_tx_int) { - flags->imask |= 0x02; - card->wandev.enable_tx_int = 0; - ++card->statistics.isr_enable_tx_int; + + case PPP_INTR_RXRDY: /* receive interrupt 0x01 (bit 0)*/ + ++card->statistics.isr_rx; + rx_intr(card); + break; + + case PPP_INTR_TXRDY: /* transmit interrupt 0x02 (bit 1)*/ + ++card->statistics.isr_tx; + flags->imask &= ~PPP_INTR_TXRDY; + dev->tbusy = 0; + card->buff_int_mode_unbusy = 1; + break; + + case PPP_INTR_CMD: /* interface command completed */ + ++Intr_test_counter; + ++card->statistics.isr_intr_test; + break; + + case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ + case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ + case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ + case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ + event_intr(card); + break; + + case PPP_INTR_TIMER: + timer_intr(card); + break; + + default: /* unexpected interrupt */ + ++card->statistics.isr_spurious; + printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", + card->devname, flags->iflag); + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + for(i = 0; i < 8; i ++) + printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); + printk(KERN_INFO "\n"); } - save_flags(host_cpu_flags); - cli(); + card->in_isr = 0; flags->iflag = 0; card->wandev.critical = 0; - restore_flags(host_cpu_flags); - if (card->buff_int_mode_unbusy) + + if(card->buff_int_mode_unbusy) { mark_bh(NET_BH); + } } /*============================================================================ * Receive interrupt handler. */ - -static void rx_intr(sdla_t * card) +static void rx_intr(sdla_t *card) { ppp_buf_ctl_t *rxbuf = card->rxmb; struct net_device *dev = card->wandev.dev; @@ -1128,160 +1577,338 @@ static void rx_intr(sdla_t * card) struct sk_buff *skb; unsigned len; void *buf; - int i, err; - ppp_flags_t *flags = card->flags; - char *ptr = &flags->iflag; + int i; + ppp_flags_t *flags = card->flags; + char *ptr = &flags->iflag; int udp_type; + + if (rxbuf->flag != 0x01) { - printk(KERN_INFO - "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", - card->devname, (unsigned) rxbuf, rxbuf->flag); - printk(KERN_INFO "%s: ID Bytes = ", card->devname); - for (i = 0; i < 8; i++) + + printk(KERN_INFO + "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", + card->devname, (unsigned)rxbuf, rxbuf->flag); + + printk(KERN_INFO "%s: ID Bytes = ",card->devname); + + for(i = 0; i < 8; i ++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); - printk(KERN_INFO "\n"); + printk(KERN_INFO "\n"); + ++card->statistics.rx_intr_corrupt_rx_bfr; return; + } + if (dev && dev->start) { - len = rxbuf->length; + + len = rxbuf->length; ppp_priv_area = dev->priv; + /* Allocate socket buffer */ skb = dev_alloc_skb(len); + if (skb != NULL) { + /* Copy data to the socket buffer */ - if (card->hw.fwid == SFID_PPP502) { - unsigned addr = (rxbuf->buf.o_p[1] << 8) + - rxbuf->buf.o_p[0]; - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); - } else { - unsigned addr = rxbuf->buf.ptr; - if ((addr + len) > card->u.p.rx_top + 1) { - unsigned tmp = card->u.p.rx_top - addr - + 1; - buf = skb_put(skb, tmp); - sdla_peek(&card->hw, addr, buf, tmp); - addr = card->u.p.rx_base; - len -= tmp; - } - buf = skb_put(skb, len); - sdla_peek(&card->hw, addr, buf, len); + unsigned addr = rxbuf->buf.ptr; + + if ((addr + len) > card->u.p.rx_top + 1) { + + unsigned tmp = card->u.p.rx_top - addr + 1; + buf = skb_put(skb, tmp); + sdla_peek(&card->hw, addr, buf, tmp); + addr = card->u.p.rx_base; + len -= tmp; } + buf = skb_put(skb, len); + sdla_peek(&card->hw, addr, buf, len); + /* Decapsulate packet */ - switch (rxbuf->proto) { - case 0x00: - skb->protocol = htons(ETH_P_IP); - break; - case 0x01: - skb->protocol = htons(ETH_P_IPX); - break; + switch (rxbuf->proto) { + + case 0x00: + skb->protocol = htons(ETH_P_IP); + break; + + case 0x01: + skb->protocol = htons(ETH_P_IPX); + break; } - udp_type = udp_pkt_type(skb, card); - if (udp_type == UDP_DRVSTATS_TYPE) { - ++ppp_priv_area->rx_intr_DRVSTATS_request; - process_udp_driver_call( - UDP_PKT_FRM_NETWORK, card, skb, - dev, ppp_priv_area); - dev_kfree_skb(skb); - } else if (udp_type == UDP_PTPIPE_TYPE) { - ++ppp_priv_area->rx_intr_PTPIPE_request; - err = process_udp_mgmt_pkt( - UDP_PKT_FRM_NETWORK, card, - skb, dev, ppp_priv_area); - dev_kfree_skb(skb); - } else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number, skb->protocol)) { - if (card->wandev.enable_IPX) { - ppp_send(card, skb->data, skb->len, ETH_P_IPX); - dev_kfree_skb(skb); + + udp_type = udp_pkt_type( skb, card ); + + if (udp_type == UDP_PTPIPE_TYPE){ + + /* Handle a UDP Request in Timer Interrupt */ + if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev, + ppp_priv_area)){ + flags->imask |= PPP_INTR_TIMER; + } + ++ppp_priv_area->rx_intr_stat.rx_intr_PIPE_request; + + + } else if (handle_IPXWAN(skb->data,card->devname, + ppp_priv_area->enable_IPX, + ppp_priv_area->network_number, + skb->protocol)) { + + /* Handle an IPXWAN packet */ + if( ppp_priv_area->enable_IPX) { + ppp_send(card, skb->data, skb->len, htons(ETH_P_IPX)); + dev_kfree_skb(skb); + + } else { ++card->wandev.stats.rx_dropped; } } else { - /* Pass it up the protocol stack */ - skb->dev = dev; - skb->mac.raw = skb->data; + /* Pass data up the protocol stack */ + skb->dev = dev; + skb->mac.raw = skb->data; + + ++card->wandev.stats.rx_packets; + card->wandev.stats.rx_bytes += skb->len; + ++ppp_priv_area->rx_intr_stat.rx_intr_bfr_passed_to_stack; netif_rx(skb); - ++card->wandev.stats.rx_packets; - card->wandev.stats.rx_bytes += skb->len; - ++ppp_priv_area->rx_intr_bfr_passed_to_stack; } + } else { + printk(KERN_INFO "%s: no socket buffers available!\n", - card->devname); + card->devname); ++card->wandev.stats.rx_dropped; - ++ppp_priv_area->rx_intr_no_socket; + ++ppp_priv_area->rx_intr_stat.rx_intr_no_socket; + + dev_kfree_skb(skb); } - } else + + } else { ++card->statistics.rx_intr_dev_not_started; + } + /* Release buffer element and calculate a pointer to the next one */ - rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00; + rxbuf->flag = 0x00; card->rxmb = ++rxbuf; - if ((void *) rxbuf > card->u.p.rxbuf_last) + if ((void*)rxbuf > card->u.p.rxbuf_last) card->rxmb = card->u.p.rxbuf_base; } -/*============================================================================ - * Transmit interrupt handler. - */ -static void tx_intr(sdla_t * card) +void event_intr (sdla_t *card) { - struct net_device *dev = card->wandev.dev; - if (!dev || !dev->start) { - ++card->statistics.tx_intr_dev_not_started; - return; + + struct net_device* dev = card->wandev.dev; + ppp_private_area_t* ppp_priv_area = dev->priv; + volatile ppp_flags_t *flags = card->flags; + + switch (flags->iflag){ + + case PPP_INTR_MODEM: /* modem status change (DCD, CTS) 0x04 (bit 2)*/ + printk (KERN_INFO "%s: Modem status: DCD=%s CTS=%s\n", + card->devname, DCD(flags->mstatus), CTS(flags->mstatus)); + + break; + + case PPP_INTR_DISC: /* Data link disconnected 0x10 (bit 4)*/ + + NEX_PRINTK (KERN_INFO "Data link disconnected intr Cause %X\n", + flags->disc_cause); + + if (flags->disc_cause & + (PPP_LOCAL_TERMINATION | PPP_DCD_CTS_DROP | + PPP_REMOTE_TERMINATION)) { + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { + Read_connection_info = 1; + remove_route (card); + } + wanpipe_set_state(card, WAN_DISCONNECTED); + show_disc_cause(card, flags->disc_cause); + ppp_priv_area->timer_int_enabled |= + TMR_INT_ENABLED_PPP_EVENT; + flags->imask |= PPP_INTR_TIMER; + } + break; + + case PPP_INTR_OPEN: /* Data link open 0x20 (bit 5)*/ + + NEX_PRINTK (KERN_INFO "%s: PPP Link Open, LCP=%s IP=%s\n", + card->devname,LCP(flags->lcp_state), + IP(flags->ip_state)); + + if (flags->lcp_state == 0x09 && + (flags->ip_state == 0x09 || flags->ipx_state == 0x09)){ + /* Initialize the polling timer and set the state + * to WAN_CONNNECTED + */ + card->state_tick = jiffies; + wanpipe_set_state(card, WAN_CONNECTED); + ppp_priv_area->timer_int_enabled |= + TMR_INT_ENABLED_PPP_EVENT; + flags->imask |= PPP_INTR_TIMER; + + } + break; + + case PPP_INTR_DROP_DTR: /* DTR drop timeout expired 0x40 bit 6 */ + + NEX_PRINTK(KERN_INFO "DTR Drop Timeout Interrrupt \n"); + if (card->u.p.ip_mode == WANOPT_PPP_PEER) { + Read_connection_info = 1; + remove_route (card); + } + wanpipe_set_state(card, WAN_DISCONNECTED); + show_disc_cause(card, flags->disc_cause); + ppp_priv_area->timer_int_enabled |= + TMR_INT_ENABLED_PPP_EVENT; + flags->imask |= PPP_INTR_TIMER; + break; + + default: + printk(KERN_INFO "%s: Error, Invalid PPP Event\n",card->devname); } - dev->tbusy = 0; - mark_bh(NET_BH); } + + +/* TIMER INTERRUPT */ + +void timer_intr (sdla_t *card) +{ + + struct net_device* dev = card->wandev.dev; + ppp_private_area_t* ppp_priv_area = dev->priv; + ppp_flags_t *flags = card->flags; + + /* Update statistics */ + if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE){ + ppp_get_err_stats(card); + if(!(--ppp_priv_area->update_comms_stats)){ + ppp_priv_area->timer_int_enabled &= + ~TMR_INT_ENABLED_UPDATE; + } + } + + /* PPIPEMON UDP request */ + + if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP){ + process_udp_mgmt_pkt(card,dev, ppp_priv_area); + ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; + } + + + /* PPP Event */ + if (ppp_priv_area->timer_int_enabled & TMR_INT_ENABLED_PPP_EVENT){ + + if (card->wandev.state == WAN_DISCONNECTED){ + poll_disconnected(card); + } + + /* If the state is CONNECTING, it means that communicatins were + * enabled. When the remote side enables its comminication we + * should get an interrupt PPP_INTR_OPEN, thus turn off polling + */ + + else if (card->wandev.state == WAN_CONNECTING){ + /* Turn off the timer interrupt */ + ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; + } + + /* If state is connected and we are in PEER mode + * poll for an IP address which will be provided by remote end. + */ + else if ((card->wandev.state == WAN_CONNECTED && + card->u.p.ip_mode == WANOPT_PPP_PEER) && + Read_connection_info){ + + card->state_tick = jiffies; + if (!read_connection_info (card)){ + card->poll = &process_route; + } + + }else{ + /* If we are using Static IP,no need to poll for + * an IP address. + */ + NEX_PRINTK(KERN_INFO "Turning off TIMER \n"); + ppp_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_PPP_EVENT; + } + + }/* End of PPP_EVENT */ + + + /* Only disable the timer interrupt if there are no udp, statistic */ + /* updates or events pending */ + if(!ppp_priv_area->timer_int_enabled) { + flags->imask &= ~PPP_INTR_TIMER; + } +} + + static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number, unsigned short proto) { int i; - if (proto == htons(ETH_P_IPX)) { - /* It's an IPX packet */ - if (!enable_IPX) { - /* Return 1 so we don't pass it up the stack. */ + + if( proto == htons(ETH_P_IPX) ) { + //It's an IPX packet + if(!enable_IPX) { + //Return 1 so we don't pass it up the stack. return 1; } } else { - /* It's not IPX so pass it up the stack. */ + //It's not IPX so pass it up the stack. return 0; } - if (sendpacket[16] == 0x90 && - sendpacket[17] == 0x04) { - /* It's IPXWAN */ - if (sendpacket[2] == 0x02 && - sendpacket[34] == 0x00) { - /* It's a timer request packet */ - printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n", devname); - /* Go through the routing options and answer no to every */ - /* option except Unnumbered RIP/SAP */ - for (i = 41; sendpacket[i] == 0x00; i += 5) { - /* 0x02 is the option for Unnumbered RIP/SAP */ - if (sendpacket[i + 4] != 0x02) { + + if( sendpacket[16] == 0x90 && + sendpacket[17] == 0x04) + { + //It's IPXWAN + + if( sendpacket[2] == 0x02 && + sendpacket[34] == 0x00) + { + //It's a timer request packet + printk(KERN_INFO "%s: Received IPXWAN Timer Request packet\n",devname); + + //Go through the routing options and answer no to every + //option except Unnumbered RIP/SAP + for(i = 41; sendpacket[i] == 0x00; i += 5) + { + //0x02 is the option for Unnumbered RIP/SAP + if( sendpacket[i + 4] != 0x02) + { sendpacket[i + 1] = 0; } } - /* Skip over the extended Node ID option */ - if (sendpacket[i] == 0x04) { + + //Skip over the extended Node ID option + if( sendpacket[i] == 0x04 ) + { i += 8; } - /* We also want to turn off all header compression opt. */ - for (; sendpacket[i] == 0x80;) { + + //We also want to turn off all header compression opt. + for(; sendpacket[i] == 0x80 ;) + { sendpacket[i + 1] = 0; i += (sendpacket[i + 2] << 8) + (sendpacket[i + 3]) + 4; } - /* Set the packet type to timer response */ + + //Set the packet type to timer response sendpacket[34] = 0x01; - printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n", devname); - } else if (sendpacket[34] == 0x02) { - /* This is an information request packet */ - printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n", devname); - /* Set the packet type to information response */ + + printk(KERN_INFO "%s: Sending IPXWAN Timer Response\n",devname); + } + else if( sendpacket[34] == 0x02 ) + { + //This is an information request packet + printk(KERN_INFO "%s: Received IPXWAN Information Request packet\n",devname); + + //Set the packet type to information response sendpacket[34] = 0x03; - /* Set the router name */ + + //Set the router name sendpacket[51] = 'P'; sendpacket[52] = 'T'; sendpacket[53] = 'P'; @@ -1290,136 +1917,81 @@ static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char sendpacket[56] = 'E'; sendpacket[57] = '-'; sendpacket[58] = CVHexToAscii(network_number >> 28); - sendpacket[59] = CVHexToAscii((network_number & 0x0F000000) >> 24); - sendpacket[60] = CVHexToAscii((network_number & 0x00F00000) >> 20); - sendpacket[61] = CVHexToAscii((network_number & 0x000F0000) >> 16); - sendpacket[62] = CVHexToAscii((network_number & 0x0000F000) >> 12); - sendpacket[63] = CVHexToAscii((network_number & 0x00000F00) >> 8); - sendpacket[64] = CVHexToAscii((network_number & 0x000000F0) >> 4); + sendpacket[59] = CVHexToAscii((network_number & 0x0F000000)>> 24); + sendpacket[60] = CVHexToAscii((network_number & 0x00F00000)>> 20); + sendpacket[61] = CVHexToAscii((network_number & 0x000F0000)>> 16); + sendpacket[62] = CVHexToAscii((network_number & 0x0000F000)>> 12); + sendpacket[63] = CVHexToAscii((network_number & 0x00000F00)>> 8); + sendpacket[64] = CVHexToAscii((network_number & 0x000000F0)>> 4); sendpacket[65] = CVHexToAscii(network_number & 0x0000000F); - for (i = 66; i < 99; i += 1) + for(i = 66; i < 99; i+= 1) + { sendpacket[i] = 0; - printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n", devname); - } else { - printk(KERN_INFO "%s: Unknown IPXWAN packet!\n", devname); + } + + printk(KERN_INFO "%s: Sending IPXWAN Information Response packet\n",devname); + } + else + { + printk(KERN_INFO "%s: Unknown IPXWAN packet!\n",devname); return 0; } - /* Set the WNodeID to our network address */ - sendpacket[35] = (unsigned char) (network_number >> 24); - sendpacket[36] = (unsigned char) ((network_number & 0x00FF0000) >> 16); - sendpacket[37] = (unsigned char) ((network_number & 0x0000FF00) >> 8); - sendpacket[38] = (unsigned char) (network_number & 0x000000FF); + + //Set the WNodeID to our network address + sendpacket[35] = (unsigned char)(network_number >> 24); + sendpacket[36] = (unsigned char)((network_number & 0x00FF0000) >> 16); + sendpacket[37] = (unsigned char)((network_number & 0x0000FF00) >> 8); + sendpacket[38] = (unsigned char)(network_number & 0x000000FF); + return 1; } else { - /* If we get here's its an IPX-data packet, so it'll get passed up the stack. */ - /* switch the network numbers */ - switch_net_numbers(sendpacket, network_number, 1); + //If we get here's its an IPX-data packet, so it'll get passed up the stack. + + //switch the network numbers + switch_net_numbers(sendpacket, network_number, 1); return 0; } } /****** Background Polling Routines ****************************************/ -/*============================================================================ - * Main polling routine. - * This routine is repeatedly called by the WANPIPE 'thread' to allow for - * time-dependent housekeeping work. - * - * Notes: - * 1. This routine may be called on interrupt context with all interrupts - * enabled. Beware! +/* All polling functions are invoked by the TIMER interrupt in the wpp_isr + * routine. */ -static void wpp_poll(sdla_t * card) -{ - struct net_device *dev = card->wandev.dev; - ppp_flags_t *adptr_flags = card->flags; - unsigned long host_cpu_flags; - ++card->statistics.poll_entry; - /* The wpp_poll is called continously by the WANPIPE thread to allow - * for line state housekeeping. However if we are in a connected state - * then we do not need to go through all the checks everytime. When in - * connected state execute wpp_poll once every second. - */ - if (card->wandev.state == WAN_CONNECTED) { - if ((jiffies - card->state_tick) < HZ) - return; - } - disable_irq(card->hw.irq); - ++card->irq_dis_poll_count; - if (test_and_set_bit(0, (void *) &card->wandev.critical)) { - ++card->statistics.poll_already_critical; - printk(KERN_INFO "%s: critical inside wpp_poll\n", - card->devname); - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && - (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); - return; - } - ++card->statistics.poll_processed; - if (dev && dev->tbusy && !(adptr_flags->imask & 0x02)) { - ++card->statistics.poll_tbusy_bad_status; - printk(KERN_INFO "%s: Wpp_Poll: tbusy = 0x01, imask = 0x%02X\n" - ,card->devname, adptr_flags->imask); - } - switch (card->wandev.state) { - case WAN_CONNECTED: - card->state_tick = jiffies; - poll_active(card); - break; - case WAN_CONNECTING: - poll_connecting(card); - break; - case WAN_DISCONNECTED: - poll_disconnected(card); - break; - default: - printk(KERN_INFO "%s: Unknown Poll State 0x%02X\n", - card->devname, card->wandev.state); - break; - } - card->wandev.critical = 0; - save_flags(host_cpu_flags); - cli(); - if ((!card->irq_dis_if_send_count) && (!(--card->irq_dis_poll_count))) - enable_irq(card->hw.irq); - restore_flags(host_cpu_flags); -} - /*============================================================================ * Monitor active link phase. */ - -static void poll_active(sdla_t * card) +static void process_route (sdla_t *card) { ppp_flags_t *flags = card->flags; - /* We check the lcp_state to see if we are in DISCONNECTED state. - * We are considered to be connected for lcp states 0x06, 0x07, 0x08 - * and 0x09. - */ - if ((flags->lcp_state <= 0x05) || (flags->disc_cause & 0x03)) { - wanpipe_set_state(card, WAN_DISCONNECTED); - show_disc_cause(card, flags->disc_cause); + struct net_device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + + if (in_dev != NULL ) { + if ((card->u.p.ip_mode == WANOPT_PPP_PEER) && + (Read_connection_info && flags->ip_state == 0x09)){ + + printk(KERN_INFO "%s: IPCP State Opened.\n", card->devname); + if (read_info( card )) { + printk(KERN_INFO + "%s: An error occurred in IP assignment.\n", + card->devname); + } else { + struct in_ifaddr *ifa = in_dev->ifa_list; + printk(KERN_INFO "%s: Assigned Lcl. Addr: %s\n", + card->devname, in_ntoa(ifa->ifa_local)); + printk(KERN_INFO "%s: Assigned Rmt. Addr: %s\n", + card->devname, in_ntoa(ifa->ifa_address)); + } + Read_connection_info = 0; + } + }else{ + printk(KERN_INFO "%s: Error: Null pointer in Poll Active\n", + card->devname); } -} - -/*============================================================================ - * Monitor link establishment phase. - * o if connection timed out, disconnect the link. - */ + card->poll = NULL; -static void poll_connecting(sdla_t * card) -{ - ppp_flags_t *flags = card->flags; - if (flags->lcp_state == 0x09) { - wanpipe_set_state(card, WAN_CONNECTED); - } else if (flags->disc_cause & 0x03) { - wanpipe_set_state(card, WAN_DISCONNECTED); - show_disc_cause(card, flags->disc_cause); - } } /*============================================================================ @@ -1427,794 +1999,796 @@ static void poll_connecting(sdla_t * card) * o if interface is up and the hold-down timeout has expired, then retry * connection. */ - -static void poll_disconnected(sdla_t * card) +static void poll_disconnected(sdla_t *card) { struct net_device *dev = card->wandev.dev; + if (dev && dev->start && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) { + wanpipe_set_state(card, WAN_CONNECTING); - if (ppp_comm_enable(card) == CMD_OK) - init_ppp_tx_rx_buff(card); + + if(ppp_comm_enable(card) == CMD_OK){ + init_ppp_tx_rx_buff( card ); + } + } } /****** Miscellaneous Functions *********************************************/ /*============================================================================ - * Configure S502 adapter. - */ - -static int config502(sdla_t * card) -{ - ppp502_conf_t cfg; - /* Prepare PPP configuration structure */ - memset(&cfg, 0, sizeof(ppp502_conf_t)); - if (card->wandev.clocking) - cfg.line_speed = bps_to_speed_code(card->wandev.bps); - cfg.txbuf_num = 4; - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; - cfg.restart_tmr = 30; - cfg.auth_rsrt_tmr = 30; - cfg.auth_wait_tmr = 300; - cfg.mdm_fail_tmr = 5; - cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 0; /* changed it from 900 */ - cfg.conf_retry = 10; - cfg.term_retry = 2; - cfg.fail_retry = 5; - cfg.auth_retry = 10; - cfg.ip_options = 0x80; - cfg.ipx_options = 0xA0; - cfg.conf_flags |= 0x0E; -/* - cfg.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; - */ - return ppp_configure(card, &cfg); -} - -/*============================================================================ * Configure S508 adapter. */ - -static int config508(sdla_t * card) +static int config508(ppp_private_area_t *ppp_priv_area, sdla_t *card) { ppp508_conf_t cfg; + struct net_device *dev = card->wandev.dev; + struct in_device *in_dev = dev->ip_ptr; + /* Prepare PPP configuration structure */ memset(&cfg, 0, sizeof(ppp508_conf_t)); + if (card->wandev.clocking) cfg.line_speed = card->wandev.bps; + if (card->wandev.interface == WANOPT_RS232) - cfg.conf_flags |= 0x0020; - cfg.conf_flags |= 0x300; /*send Configure-Request packets forever */ - cfg.txbuf_percent = 60; /* % of Tx bufs */ - cfg.mtu_local = card->wandev.mtu; - cfg.mtu_remote = card->wandev.mtu; - cfg.restart_tmr = 30; - cfg.auth_rsrt_tmr = 30; - cfg.auth_wait_tmr = 300; - cfg.mdm_fail_tmr = 100; - cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 0; /* changed it from 900 */ - cfg.conf_retry = 10; - cfg.term_retry = 2; - cfg.fail_retry = 5; - cfg.auth_retry = 10; - cfg.ip_options = 0x80; - cfg.ipx_options = 0xA0; -/* - cfg.ip_local = dev->pa_addr; - cfg.ip_remote = dev->pa_dstaddr; - */ + cfg.conf_flags |= INTERFACE_LEVEL_RS232; + + cfg.conf_flags |= DONT_TERMINATE_LNK_MAX_CONFIG; /*send Configure-Request packets forever*/ + cfg.txbuf_percent = PERCENT_TX_BUFF; /* % of Tx bufs */ + cfg.mtu_local = card->wandev.mtu; + cfg.mtu_remote = card->wandev.mtu; /* Default */ + cfg.restart_tmr = TIME_BETWEEN_CONF_REQ; /* 30 = 3sec */ + cfg.auth_rsrt_tmr = TIME_BETWEEN_PAP_CHAP_REQ; /* 30 = 3sec */ + cfg.auth_wait_tmr = WAIT_PAP_CHAP_WITHOUT_REPLY; /* 300 = 30s */ + cfg.mdm_fail_tmr = WAIT_AFTER_DCD_CTS_LOW; /* 5 = 0.5s */ + cfg.dtr_drop_tmr = TIME_DCD_CTS_LOW_AFTER_LNK_DOWN; /* 10 = 1s */ + cfg.connect_tmout = WAIT_DCD_HIGH_AFTER_ENABLE_COMM; /* 900 = 90s */ + cfg.conf_retry = MAX_CONF_REQ_WITHOUT_REPLY; /* 10 = 1s */ + cfg.term_retry = MAX_TERM_REQ_WITHOUT_REPLY; /* 2 times */ + cfg.fail_retry = NUM_CONF_NAK_WITHOUT_REPLY; /* 5 times */ + cfg.auth_retry = NUM_AUTH_REQ_WITHOUT_REPLY; /* 10 times */ + + + if( !card->u.p.authenticator ) { + printk(KERN_INFO "%s: Device is not configured as an authenticator\n", + card->devname); + cfg.auth_options = NO_AUTHENTICATION; + }else{ + printk(KERN_INFO "%s: Device is configured as an authenticator\n", + card->devname); + cfg.auth_options = INBOUND_AUTH; + } + if( ppp_priv_area->pap == WANOPT_YES){ + cfg.auth_options |=PAP_AUTH; + printk(KERN_INFO "%s: Pap enabled\n", card->devname); + } + if( ppp_priv_area->chap == WANOPT_YES){ + cfg.auth_options |= CHAP_AUTH; + printk(KERN_INFO "%s: Chap enabled\n", card->devname); + } + + + if (ppp_priv_area->enable_IPX == WANOPT_YES){ + cfg.ipx_options = ENABLE_IPX | ROUTING_PROT_DEFAULT; + }else{ + cfg.ipx_options = DISABLE_IPX; + } + + switch (card->u.p.ip_mode) { + + case WANOPT_PPP_STATIC: + + cfg.ip_options = L_AND_R_IP_NO_ASSIG | + ENABLE_IP; + cfg.ip_local = in_dev->ifa_list->ifa_local; + cfg.ip_remote = in_dev->ifa_list->ifa_address; + NEX_PRINTK(KERN_INFO "Local %s Remote %s Name %s\n", + in_ntoa(cfg.ip_local), + in_ntoa(cfg.ip_remote), + dev->name); + break; + + case WANOPT_PPP_PEER: + cfg.ip_options = L_IP_REMOTE_ASSIG | + R_IP_REMOTE_ASSIG | + ENABLE_IP; + cfg.ip_local = 0x00; + cfg.ip_remote = 0x00; + break; + + } return ppp_configure(card, &cfg); } /*============================================================================ * Show disconnection cause. */ - -static void show_disc_cause(sdla_t * card, unsigned cause) +static void show_disc_cause(sdla_t *card, unsigned cause) { - if (cause & 0x0002) - printk(KERN_INFO "%s: link terminated by peer\n", - card->devname); - else if (cause & 0x0004) - printk(KERN_INFO "%s: link terminated by user\n", - card->devname); - else if (cause & 0x0008) + if (cause & 0x0802) + + printk(KERN_INFO "%s: link terminated by peer\n", + card->devname); + + else if (cause & 0x0004) + + printk(KERN_INFO "%s: link terminated by user\n", + card->devname); + + else if (cause & 0x0008) + printk(KERN_INFO "%s: authentication failed\n", card->devname); - else if (cause & 0x0010) - printk(KERN_INFO - "%s: authentication protocol negotiation failed\n", - card->devname); - else if (cause & 0x0020) - printk(KERN_INFO - "%s: peer's request for authentication rejected\n", - card->devname); - else if (cause & 0x0040) - printk(KERN_INFO "%s: MRU option rejected by peer\n", - card->devname); - else if (cause & 0x0080) - printk(KERN_INFO "%s: peer's MRU was too small\n", - card->devname); - else if (cause & 0x0100) - printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", - card->devname); - else if (cause & 0x0200) - printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" - ,card->devname); - else if (cause & 0x0400) + + else if (cause & 0x0010) + + printk(KERN_INFO + "%s: authentication protocol negotiation failed\n", + card->devname); + + else if (cause & 0x0020) + printk(KERN_INFO - "%s: failed to negotiate peer's IPXCP options\n", - card->devname); -} + "%s: peer's request for authentication rejected\n", + card->devname); -/*============================================================================ - * Convert line speed in bps to a number used by S502 code. - */ + else if (cause & 0x0040) + + printk(KERN_INFO "%s: MRU option rejected by peer\n", + card->devname); -static unsigned char bps_to_speed_code(unsigned long bps) -{ - unsigned char number; - if (bps <= 1200) - number = 0x01; - else if (bps <= 2400) - number = 0x02; - else if (bps <= 4800) - number = 0x03; - else if (bps <= 9600) - number = 0x04; - else if (bps <= 19200) - number = 0x05; - else if (bps <= 38400) - number = 0x06; - else if (bps <= 45000) - number = 0x07; - else if (bps <= 56000) - number = 0x08; - else if (bps <= 64000) - number = 0x09; - else if (bps <= 74000) - number = 0x0A; - else if (bps <= 112000) - number = 0x0B; - else if (bps <= 128000) - number = 0x0C; - else - number = 0x0D; - return number; -} + else if (cause & 0x0080) + + printk(KERN_INFO "%s: peer's MRU was too small\n", + card->devname); -/*============================================================================ - * Process UDP call of type DRVSTATS. - */ + else if (cause & 0x0100) -static int process_udp_driver_call(char udp_pkt_src, sdla_t * card, struct sk_buff *skb, struct net_device *dev, ppp_private_area_t * ppp_priv_area) -{ - unsigned char *sendpacket; - unsigned char buf2[5]; - unsigned char *data; - unsigned char *buf; - unsigned int len; - ppp_mbox_t *mbox = card->mbox; - struct sk_buff *new_skb; - int err; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) { - printk(KERN_INFO - "%s: Error allocating memory for UDP DRIVER STATS cmnd0x%02X" - ,card->devname, data[45]); - ++ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[45]) { - /* PPIPE_DRIVER_STATISTICS */ - case 0x26: - *(unsigned long *) &data[60] = - ppp_priv_area->if_send_entry; - *(unsigned long *) &data[64] = - ppp_priv_area->if_send_skb_null; - *(unsigned long *) &data[68] = - ppp_priv_area->if_send_broadcast; - *(unsigned long *) &data[72] = - ppp_priv_area->if_send_multicast; - *(unsigned long *) &data[76] = - ppp_priv_area->if_send_critical_ISR; - *(unsigned long *) &data[80] = - ppp_priv_area->if_send_critical_non_ISR; - *(unsigned long *) &data[84] = - ppp_priv_area->if_send_busy; - *(unsigned long *) &data[88] = - ppp_priv_area->if_send_busy_timeout; - *(unsigned long *) &data[92] = - ppp_priv_area->if_send_DRVSTATS_request; - *(unsigned long *) &data[96] = - ppp_priv_area->if_send_PTPIPE_request; - *(unsigned long *) &data[100] = - ppp_priv_area->if_send_wan_disconnected; - *(unsigned long *) &data[104] = - ppp_priv_area->if_send_adptr_bfrs_full; - *(unsigned long *) &data[108] = - ppp_priv_area->if_send_protocol_error; - *(unsigned long *) &data[112] = - ppp_priv_area->if_send_tx_int_enabled; - *(unsigned long *) &data[116] = - ppp_priv_area->if_send_bfr_passed_to_adptr; - *(unsigned long *) &data[118] = - card->irq_dis_if_send_count; - mbox->cmd.length = 62; - break; - case 0x27: - *(unsigned long *) &data[60] = card->statistics.isr_entry; - *(unsigned long *) &data[64] = - card->statistics.isr_already_critical; - *(unsigned long *) &data[68] = card->statistics.isr_rx; - *(unsigned long *) &data[72] = card->statistics.isr_tx; - *(unsigned long *) &data[76] = - card->statistics.isr_intr_test; - *(unsigned long *) &data[80] = - card->statistics.isr_spurious; - *(unsigned long *) &data[84] = - card->statistics.isr_enable_tx_int; - *(unsigned long *) &data[88] = - card->statistics.rx_intr_corrupt_rx_bfr; - *(unsigned long *) &data[92] = - ppp_priv_area->rx_intr_no_socket; - *(unsigned long *) &data[96] = - ppp_priv_area->rx_intr_DRVSTATS_request; - *(unsigned long *) &data[100] = - ppp_priv_area->rx_intr_PTPIPE_request; - *(unsigned long *) &data[104] = - ppp_priv_area->rx_intr_bfr_passed_to_stack; - *(unsigned long *) &data[108] = - card->statistics.rx_intr_dev_not_started; - *(unsigned long *) &data[112] = - card->statistics.tx_intr_dev_not_started; - mbox->cmd.length = 56; - break; - case 0x28: - *(unsigned long *) &data[60] = - ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; - *(unsigned long *) &data[64] = - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; - *(unsigned long *) &data[68] = - ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; - *(unsigned long *) &data[72] = - ppp_priv_area-> - UDP_PTPIPE_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[76] = - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[80] = - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; - *(unsigned long *) &data[84] = - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; - *(unsigned long *) &data[88] = - ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; - *(unsigned long *) &data[92] = - ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err; - *(unsigned long *) &data[96] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - *(unsigned long *) &data[100] = - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - *(unsigned long *) &data[104] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_passed_to_adptr; - *(unsigned long *) &data[108] = - ppp_priv_area-> - UDP_DRVSTATS_mgmt_passed_to_stack; - *(unsigned long *) &data[112] = - ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; - *(unsigned long *) &data[116] = - card->statistics.poll_entry; - *(unsigned long *) &data[120] = - card->statistics.poll_already_critical; - *(unsigned long *) &data[124] = - card->statistics.poll_processed; - *(unsigned long *) &data[126] = - card->irq_dis_poll_count; - mbox->cmd.length = 70; - break; - default: - /* it's a board command */ - memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&mbox->data, &sendpacket[60], - mbox->cmd.length); - } - /* run the command on the board */ - err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) { - ppp_error(card, err, mbox); - ++ppp_priv_area-> - UDP_DRVSTATS_mgmt_adptr_cmnd_timeout; - break; - } - ++ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK; - /* copy the result back to our buffer */ - memcpy(data, sendpacket, skb->len); - memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&data[60], &mbox->data, mbox->cmd.length); - } - } - /* Fill UDP TTL */ - data[8] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { - ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr; - ppp_send(card, data, len, skb->protocol); - } else { - /* Pass it up the stack - Allocate socket buffer */ - if ((new_skb = dev_alloc_skb(len)) != NULL) { - /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - ++ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack; - /* Decapsulate packet and pass it up the protocol - stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; - netif_rx(new_skb); - } else { - ++ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket; - printk(KERN_INFO "no socket buffers available!\n"); - } - } - kfree(data); - return 0; + printk(KERN_INFO "%s: failed to negotiate peer's LCP options\n", + card->devname); + + else if (cause & 0x0200) + + printk(KERN_INFO "%s: failed to negotiate peer's IPCP options\n" + , card->devname); + + else if (cause & 0x0400) + + printk(KERN_INFO + "%s: failed to negotiate peer's IPXCP options\n", + card->devname); } /*============================================================================= * Process UDP call of type PTPIPEAB. */ - -static int process_udp_mgmt_pkt(char udp_pkt_src, sdla_t * card, - struct sk_buff *skb, struct net_device *dev, - ppp_private_area_t * ppp_priv_area) +static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, + ppp_private_area_t *ppp_priv_area ) { - unsigned char *sendpacket; unsigned char buf2[5]; - unsigned char *data; unsigned char *buf; unsigned int frames, len; struct sk_buff *new_skb; - unsigned short buffer_length, real_len; + unsigned short data_length, buffer_length, real_len; unsigned long data_ptr; int udp_mgmt_req_valid = 1; ppp_mbox_t *mbox = card->mbox; struct timeval tv; int err; - sendpacket = skb->data; - memcpy(&buf2, &card->wandev.udp_port, 2); - if ((data = kmalloc(2000, GFP_ATOMIC)) == NULL) { - printk(KERN_INFO - "%s: Error allocating memory for UDP management cmnd0x%02X" - ,card->devname, data[45]); - ++ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err; - return 1; - } - memcpy(data, sendpacket, skb->len); - switch (data[45]) { + ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t*)&ppp_priv_area->udp_pkt_data; + + memcpy(&buf2, &card->wandev.udp_port, 2 ); + + + switch(ppp_udp_pkt->cblock.command) { + /* FT1 MONITOR STATUS */ - case 0x80: - if (card->hw.fwid != SFID_PPP508) { - ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err; - udp_mgmt_req_valid = 0; - break; - } + case FT1_MONITOR_STATUS_CTRL: + /* PPIPE_ENABLE_TRACING */ - case 0x20: + case PPIPE_ENABLE_TRACING: + /* PPIPE_DISABLE_TRACING */ - case 0x21: + case PPIPE_DISABLE_TRACING: + /* PPIPE_GET_TRACE_INFO */ - case 0x22: + case PPIPE_GET_TRACE_INFO: + /* SET FT1 MODE */ - case 0x81: - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { - ++ppp_priv_area->UDP_PTPIPE_mgmt_direction_err; - udp_mgmt_req_valid = 0; - } - break; - default: - break; - } - if (!udp_mgmt_req_valid) { + case SET_FT1_MODE: + if(ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + ++ppp_priv_area->pipe_mgmt_stat. + UDP_PIPE_mgmt_direction_err; + udp_mgmt_req_valid = 0; + } + break; + + default: + break; + } + + if(!udp_mgmt_req_valid) { + /* set length to 0 */ - data[46] = data[47] = 0; - /* set return code */ - data[48] = 0xCD; - } else { - switch (data[45]) { - /* PPIPE_ENABLE_TRACING */ - case 0x20: - if (!TracingEnabled) { + ppp_udp_pkt->cblock.length = 0x00; + + /* set return code */ + ppp_udp_pkt->cblock.result = 0xCD; + + } else { + /* Initialize the trace element */ + trace_element_t trace_element; + + switch (ppp_udp_pkt->cblock.command){ + + /* PPIPE_ENABLE_TRACING */ + case PPIPE_ENABLE_TRACING: + if (!card->TracingEnabled) { + /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x33; - mbox->cmd.length = 1; - mbox->data[0] = 0x03; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) { + mbox->cmd.command = PPP_DATALINE_MONITOR; + mbox->cmd.length = 0x01; + mbox->data[0] = ppp_udp_pkt->data[0]; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) { + ppp_error(card, err, mbox); - TracingEnabled = 0; + card->TracingEnabled = 0; + /* set the return code */ - data[48] = mbox->cmd.result; - mbox->cmd.length = 0; - break; - } - if (card->hw.fwid == SFID_PPP502) { - sdla_peek(&card->hw, 0x9000, &buf2, 2); - } else { - sdla_peek(&card->hw, 0xC000, &buf2, 2); - } - curr_trace_addr = 0; - memcpy(&curr_trace_addr, &buf2, 2); - start_trace_addr = curr_trace_addr; - /* MAX_SEND_BUFFER_SIZE -sizeof(UDP_MGMT_PACKET) - - 41 */ - available_buffer_space = 1926; - } - data[48] = 0; - mbox->cmd.length = 0; - TracingEnabled = 1; - break; - /* PPIPE_DISABLE_TRACING */ - case 0x21: - if (TracingEnabled) { + + ppp_udp_pkt->cblock.result = mbox->cmd.result; + mbox->cmd.length = 0; + break; + } + + sdla_peek(&card->hw, 0xC000, &buf2, 2); + + ppp_priv_area->curr_trace_addr = 0; + memcpy(&ppp_priv_area->curr_trace_addr, &buf2, 2); + ppp_priv_area->start_trace_addr = + ppp_priv_area->curr_trace_addr; + ppp_priv_area->end_trace_addr = + ppp_priv_area->start_trace_addr + END_OFFSET; + + /* MAX_SEND_BUFFER_SIZE - 28 (IP header) + - 32 (ppipemon CBLOCK) */ + available_buffer_space = MAX_LGTH_UDP_MGNT_PKT - + sizeof(ip_pkt_t)- + sizeof(udp_pkt_t)- + sizeof(wp_mgmt_t)- + sizeof(cblock_t); + } + ppp_udp_pkt->cblock.result = 0; + mbox->cmd.length = 0; + card->TracingEnabled = 1; + break; + + /* PPIPE_DISABLE_TRACING */ + case PPIPE_DISABLE_TRACING: + + if(card->TracingEnabled) { + /* OPERATE_DATALINE_MONITOR */ - mbox->cmd.command = 0x3; - mbox->cmd.length = 1; - mbox->data[0] = 0x00; - err = sdla_exec(mbox) ? - mbox->cmd.result : CMD_TIMEOUT; - } - /*set return code */ - data[48] = 0; + mbox->cmd.command = 0x33; + mbox->cmd.length = 1; + mbox->data[0] = 0x00; + err = sdla_exec(mbox) ? + mbox->cmd.result : CMD_TIMEOUT; + + } + + /*set return code*/ + ppp_udp_pkt->cblock.result = 0; mbox->cmd.length = 0; - TracingEnabled = 0; + card->TracingEnabled = 0; break; - /* PPIPE_GET_TRACE_INFO */ - case 0x22: - if (TracingEnabled) { - buffer_length = 0; - /* frames < NUM_TRACE_FRAMES */ - for (frames = 0; frames < 62; frames += 1) { - sdla_peek(&card->hw, curr_trace_addr, - &buf2, 1); - /* no data on board so exit */ - if (buf2[0] == 0x00) - break; - /*1+sizeof(FRAME_DATA) = 9 */ - if ((available_buffer_space - - buffer_length) < 9) { - /*indicate we have more frames - on board and exit */ - data[60] |= 0x02; + + /* PPIPE_GET_TRACE_INFO */ + case PPIPE_GET_TRACE_INFO: + + if(!card->TracingEnabled) { + /* set return code */ + ppp_udp_pkt->cblock.result = 1; + mbox->cmd.length = 0; + } + + buffer_length = 0; + + /* frames < 62, where 62 is the number of trace + information elements. There is in total 496 + bytes of space and each trace information + element is 8 bytes. + */ + for ( frames=0; frames<62; frames++) { + + trace_pkt_t *trace_pkt = (trace_pkt_t *) + &ppp_udp_pkt->data[buffer_length]; + + /* Read the whole trace packet */ + sdla_peek(&card->hw, ppp_priv_area->curr_trace_addr, + &trace_element, sizeof(trace_element_t)); + + /* no data on board so exit */ + if( trace_element.opp_flag == 0x00 ) + break; + + data_ptr = trace_element.trace_data_ptr; + + /* See if there is actual data on the trace buffer */ + if (data_ptr){ + data_length = trace_element.trace_length; + }else{ + data_length = 0; + ppp_udp_pkt->data[0] |= 0x02; + } + + //FIXME: Do we need this check + if ((available_buffer_space - buffer_length) + < (sizeof(trace_element_t)+1)){ + + /*indicate we have more frames + * on board and exit + */ + ppp_udp_pkt->data[0] |= 0x02; + break; + } + + trace_pkt->status = trace_element.trace_type; + trace_pkt->time_stamp = trace_element.trace_time_stamp; + trace_pkt->real_length = trace_element.trace_length; + + real_len = trace_element.trace_length; + + if(data_ptr == 0){ + trace_pkt->data_avail = 0x00; + }else{ + /* we can take it next time */ + if ((available_buffer_space - buffer_length)< + (real_len + sizeof(trace_pkt_t))){ + + ppp_udp_pkt->data[0] |= 0x02; break; - } - /* get frame status */ - sdla_peek(&card->hw, curr_trace_addr + - 0x01, &data[60 + buffer_length], 1); - /* get time stamp */ - sdla_peek(&card->hw, curr_trace_addr + - 0x06, &data[64 + buffer_length], 2); - /* get frame length */ - sdla_peek(&card->hw, curr_trace_addr + - 0x02, &data[62 + buffer_length], 2); - /* get pointer to real data */ - sdla_peek(&card->hw, curr_trace_addr + - 0x04, &buf2, 2); - data_ptr = 0; - memcpy(&data_ptr, &buf2, 2); - /* see if we can fit the frame into the - user buffer */ - memcpy(&real_len, - &data[62 + buffer_length], 2); - if ((data_ptr == 0) || - ((real_len + 8) > - available_buffer_space)) { - data[61 + buffer_length] = 0x00; - } else { - /* we can take it next time */ - if ((available_buffer_space - - buffer_length) < - (real_len + 8)) { - data[60] |= 0x02; - break; - } - /* ok, get the frame */ - data[61 + buffer_length] = 0x01; - /* get the data */ - sdla_peek(&card->hw, data_ptr, - &data[66 + buffer_length], - real_len); - /* zero the opp flag to - show we got the frame */ - buf2[0] = 0x00; - sdla_poke(&card->hw, - curr_trace_addr, &buf2, 1); - /* now move onto the next - frame */ - curr_trace_addr += 8; - /* check if we passed the last - address */ - if (curr_trace_addr >= - start_trace_addr + 0x1F0) { - curr_trace_addr = - start_trace_addr; - } - /* update buffer length and make sure its even */ - if (data[61 + buffer_length] - == 0x01) { - buffer_length += - real_len - 1; - } - /* for the header */ - buffer_length += 8; - if (buffer_length & 0x0001) - buffer_length += 1; - } + } + trace_pkt->data_avail = 0x01; + + /* get the data */ + sdla_peek(&card->hw, data_ptr, + &trace_pkt->data, + real_len); + } + /* zero the opp flag to + show we got the frame */ + buf2[0] = 0x00; + sdla_poke(&card->hw, ppp_priv_area->curr_trace_addr, + &buf2, 1); + + /* now move onto the next + frame */ + ppp_priv_area->curr_trace_addr += 8; + + /* check if we passed the last address */ + if ( ppp_priv_area->curr_trace_addr >= + ppp_priv_area->end_trace_addr){ + + ppp_priv_area->curr_trace_addr = + ppp_priv_area->start_trace_addr; } - /* ok now set the total number of frames passed - in the high 5 bits */ - data[60] = (frames << 2) | data[60]; - /* set the data length */ - mbox->cmd.length = buffer_length; - memcpy(&data[46], &buffer_length, 2); - /* set return code */ - data[48] = 0; - } else { - /* set return code */ - data[48] = 1; - mbox->cmd.length = 0; + + /* update buffer length and make sure its even */ + + if ( trace_pkt->data_avail == 0x01 ) { + buffer_length += real_len - 1; + } + + /* for the header */ + buffer_length += 8; + + if( buffer_length & 0x0001 ) + buffer_length += 1; } - break; - /* PPIPE_GET_IBA_DATA */ - case 0x23: + + /* ok now set the total number of frames passed + in the high 5 bits */ + ppp_udp_pkt->data[0] |= (frames << 2); + + /* set the data length */ + mbox->cmd.length = buffer_length; + ppp_udp_pkt->cblock.length = buffer_length; + + /* set return code */ + ppp_udp_pkt->cblock.result = 0; + break; + + /* PPIPE_GET_IBA_DATA */ + case PPIPE_GET_IBA_DATA: + mbox->cmd.length = 0x09; - if (card->hw.fwid == SFID_PPP502) { - sdla_peek(&card->hw, 0xA003, &data[60], - mbox->cmd.length); - } else { - sdla_peek(&card->hw, 0xF003, &data[60], - mbox->cmd.length); - } + + sdla_peek(&card->hw, 0xF003, &ppp_udp_pkt->data, + mbox->cmd.length); + /* set the length of the data */ - data[46] = 0x09; + ppp_udp_pkt->cblock.length = 0x09; + /* set return code */ - data[48] = 0x00; + ppp_udp_pkt->cblock.result = 0x00; + break; - /* PPIPE_KILL_BOARD */ - case 0x24: + + /* PPIPE_KILL_BOARD */ + case PPIPE_KILL_BOARD: break; - /* PPIPE_FT1_READ_STATUS */ - case 0x25: - sdla_peek(&card->hw, 0xF020, &data[60], 2); - data[46] = 2; - data[47] = 0; - data[48] = 0; + + /* PPIPE_FT1_READ_STATUS */ + case PPIPE_FT1_READ_STATUS: + sdla_peek(&card->hw, 0xF020, &ppp_udp_pkt->data, 2); + ppp_udp_pkt->cblock.length = 2; + ppp_udp_pkt->cblock.result = 0; mbox->cmd.length = 2; break; - case 0x29: - init_ppp_priv_struct(ppp_priv_area); - init_global_statistics(card); + + case PPIPE_FLUSH_DRIVER_STATS: + init_ppp_priv_struct( ppp_priv_area ); + init_global_statistics( card ); mbox->cmd.length = 0; break; - case 0x30: - do_gettimeofday(&tv); - ppp_priv_area->router_up_time = tv.tv_sec - - ppp_priv_area->router_start_time; - *(unsigned long *) &data[60] = - ppp_priv_area->router_up_time; + + case PPIPE_ROUTER_UP_TIME: + + do_gettimeofday( &tv ); + ppp_priv_area->router_up_time = tv.tv_sec - + ppp_priv_area->router_start_time; + *(unsigned long *)&ppp_udp_pkt->data = ppp_priv_area->router_up_time; mbox->cmd.length = 4; break; - /* FT1 MONITOR STATUS */ - case 0x80: + + /* FT1 MONITOR STATUS */ + case FT1_MONITOR_STATUS_CTRL: + /* Enable FT1 MONITOR STATUS */ - if (data[60] == 1) { - if (rCount++ != 0) { - data[48] = 0; - mbox->cmd.length = 1; - break; - } - } - /* Disable FT1 MONITOR STATUS */ - if (data[60] == 0) { - if (--rCount != 0) { - data[48] = 0; - mbox->cmd.length = 1; - break; - } - } + if( ppp_udp_pkt->data[0] == 1) { + + if( rCount++ != 0 ) { + ppp_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + + /* Disable FT1 MONITOR STATUS */ + if( ppp_udp_pkt->data[0] == 0) { + + if( --rCount != 0) { + ppp_udp_pkt->cblock.result = 0; + mbox->cmd.length = 1; + break; + } + } + + /* PPIPE_DRIVER_STATISTICS */ + case PPIPE_DRIVER_STAT_IFSEND: + printk(KERN_INFO "Getting IF_SEND Drivers Statistics\n"); + memcpy(&ppp_udp_pkt->data, &ppp_priv_area->if_send_stat, + sizeof(if_send_stat_t)); + + + ppp_udp_pkt->cblock.result = 0; + ppp_udp_pkt->cblock.length = sizeof(if_send_stat_t); + mbox->cmd.length = sizeof(if_send_stat_t); + break; + + case PPIPE_DRIVER_STAT_INTR: + memcpy(&ppp_udp_pkt->data, &card->statistics, + sizeof(global_stats_t)); + + memcpy(&ppp_udp_pkt->data+sizeof(global_stats_t), + &ppp_priv_area->rx_intr_stat, + sizeof(rx_intr_stat_t)); + + ppp_udp_pkt->cblock.result = 0; + ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + mbox->cmd.length = ppp_udp_pkt->cblock.length; + break; + + case PPIPE_DRIVER_STAT_GEN: + memcpy( &ppp_udp_pkt->data, + &ppp_priv_area->pipe_mgmt_stat, + sizeof(pipe_mgmt_stat_t)); + + memcpy(&ppp_udp_pkt->data+sizeof(pipe_mgmt_stat_t), + &card->statistics, sizeof(global_stats_t)); + + ppp_udp_pkt->cblock.result = 0; + ppp_udp_pkt->cblock.length = sizeof(global_stats_t)+ + sizeof(rx_intr_stat_t); + mbox->cmd.length = ppp_udp_pkt->cblock.length; + break; + + default: + /* it's a board command */ - memcpy(&mbox->cmd, &sendpacket[45], sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&mbox->data, &sendpacket[60], + mbox->cmd.command = ppp_udp_pkt->cblock.command; + mbox->cmd.length = ppp_udp_pkt->cblock.length; + + if(mbox->cmd.length) { + memcpy(&mbox->data,(unsigned char *)ppp_udp_pkt->data, mbox->cmd.length); - } + } + /* run the command on the board */ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + if (err != CMD_OK) { - ppp_error(card, err, mbox); - ++ppp_priv_area-> - UDP_PTPIPE_mgmt_adptr_cmnd_timeout; + + ppp_error(card, err, mbox); + ++ppp_priv_area->pipe_mgmt_stat. + UDP_PIPE_mgmt_adptr_cmnd_timeout; break; } - ++ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK; + + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_adptr_cmnd_OK; + /* copy the result back to our buffer */ - memcpy(data, sendpacket, skb->len); - memcpy(&data[45], &mbox->cmd, sizeof(ppp_cmd_t)); - if (mbox->cmd.length) { - memcpy(&data[60], &mbox->data, mbox->cmd.length); - } - } /* end of switch */ - } /* end of else */ - /* Fill UDP TTL */ - data[8] = card->wandev.ttl; - len = reply_udp(data, mbox->cmd.length); - if (udp_pkt_src == UDP_PKT_FRM_NETWORK) { - ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr; - ppp_send(card, data, len, skb->protocol); - } else { + memcpy(&ppp_udp_pkt->cblock,mbox, sizeof(cblock_t)); + + if(mbox->cmd.length) { + memcpy(&ppp_udp_pkt->data,&mbox->data,mbox->cmd.length); + } + + } /* end of switch */ + } /* end of else */ + + /* Fill UDP TTL */ + ppp_udp_pkt->ip_pkt.ttl = card->wandev.ttl; + len = reply_udp(ppp_priv_area->udp_pkt_data, mbox->cmd.length); + + if (ppp_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK) { + + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_adptr; + ppp_send(card,ppp_priv_area->udp_pkt_data,len,ppp_priv_area->protocol); + + } else { + /* Pass it up the stack - Allocate socket buffer */ + Allocate socket buffer */ if ((new_skb = dev_alloc_skb(len)) != NULL) { + /* copy data into new_skb */ - buf = skb_put(new_skb, len); - memcpy(buf, data, len); - ++ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack; - /* Decapsulate packet and pass it up the protocol + + buf = skb_put(new_skb, len); + memcpy(buf,ppp_priv_area->udp_pkt_data, len); + + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_passed_to_stack; + + /* Decapsulate packet and pass it up the protocol stack */ - new_skb->protocol = htons(ETH_P_IP); - new_skb->dev = dev; - new_skb->mac.raw = new_skb->data; + new_skb->protocol = htons(ETH_P_IP); + new_skb->dev = dev; + new_skb->mac.raw = new_skb->data; netif_rx(new_skb); + } else { - ++ppp_priv_area->UDP_PTPIPE_mgmt_no_socket; + + ++ppp_priv_area->pipe_mgmt_stat.UDP_PIPE_mgmt_no_socket; printk(KERN_INFO "no socket buffers available!\n"); - } - } - kfree(data); - return 0; + } + } + + ppp_priv_area->udp_pkt_lgth = 0; + + return; } /*============================================================================= * Initial the ppp_private_area structure. */ - -static void init_ppp_priv_struct(ppp_private_area_t * ppp_priv_area) +static void init_ppp_priv_struct( ppp_private_area_t *ppp_priv_area ) { - ppp_priv_area->if_send_entry = 0; - ppp_priv_area->if_send_skb_null = 0; - ppp_priv_area->if_send_broadcast = 0; - ppp_priv_area->if_send_multicast = 0; - ppp_priv_area->if_send_critical_ISR = 0; - ppp_priv_area->if_send_critical_non_ISR = 0; - ppp_priv_area->if_send_busy = 0; - ppp_priv_area->if_send_busy_timeout = 0; - ppp_priv_area->if_send_DRVSTATS_request = 0; - ppp_priv_area->if_send_PTPIPE_request = 0; - ppp_priv_area->if_send_wan_disconnected = 0; - ppp_priv_area->if_send_adptr_bfrs_full = 0; - ppp_priv_area->if_send_bfr_passed_to_adptr = 0; - ppp_priv_area->rx_intr_no_socket = 0; - ppp_priv_area->rx_intr_DRVSTATS_request = 0; - ppp_priv_area->rx_intr_PTPIPE_request = 0; - ppp_priv_area->rx_intr_bfr_not_passed_to_stack = 0; - ppp_priv_area->rx_intr_bfr_passed_to_stack = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_kmalloc_err = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_type_err = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_direction_err = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_timeout = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_adptr_cmnd_OK = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_adptr = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_passed_to_stack = 0; - ppp_priv_area->UDP_PTPIPE_mgmt_no_socket = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_kmalloc_err = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_type_err = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_direction_err = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_timeout = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_adptr_cmnd_OK = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_adptr = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_passed_to_stack = 0; - ppp_priv_area->UDP_DRVSTATS_mgmt_no_socket = 0; + + memset(&ppp_priv_area->if_send_stat, 0, sizeof(if_send_stat_t)); + memset(&ppp_priv_area->rx_intr_stat, 0, sizeof(rx_intr_stat_t)); + memset(&ppp_priv_area->pipe_mgmt_stat, 0, sizeof(pipe_mgmt_stat_t)); } /*============================================================================ * Initialize Global Statistics */ - -static void init_global_statistics(sdla_t * card) +static void init_global_statistics( sdla_t *card ) { - card->statistics.isr_entry = 0; - card->statistics.isr_already_critical = 0; - card->statistics.isr_tx = 0; - card->statistics.isr_rx = 0; - card->statistics.isr_intr_test = 0; - card->statistics.isr_spurious = 0; - card->statistics.isr_enable_tx_int = 0; - card->statistics.rx_intr_corrupt_rx_bfr = 0; - card->statistics.rx_intr_dev_not_started = 0; - card->statistics.tx_intr_dev_not_started = 0; - card->statistics.poll_entry = 0; - card->statistics.poll_already_critical = 0; - card->statistics.poll_processed = 0; - card->statistics.poll_tbusy_bad_status = 0; + memset(&card->statistics, 0, sizeof(global_stats_t)); } /*============================================================================ * Initialize Receive and Transmit Buffers. */ - -static void init_ppp_tx_rx_buff(sdla_t * card) +static void init_ppp_tx_rx_buff( sdla_t *card ) { - if (card->hw.fwid == SFID_PPP502) { - ppp502_buf_info_t *info = - (void *) (card->hw.dpmbase + PPP502_BUF_OFFS); - card->u.p.txbuf_base = - (void *) (card->hw.dpmbase + info->txb_offs); - card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + - (info->txb_num - 1); - card->u.p.rxbuf_base = - (void *) (card->hw.dpmbase + info->rxb_offs); - card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + - (info->rxb_num - 1); + ppp508_buf_info_t* info; + + if (card->hw.type == SDLA_S514) { + + info = (void*)(card->hw.dpmbase + PPP514_BUF_OFFS); + + card->u.p.txbuf_base = (void*)(card->hw.dpmbase + + info->txb_ptr); + + card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + + (info->txb_num - 1); + + card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + + info->rxb_ptr); + + card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + + (info->rxb_num - 1); + } else { - ppp508_buf_info_t *info = - (void *) (card->hw.dpmbase + PPP508_BUF_OFFS); - card->u.p.txbuf_base = (void *) (card->hw.dpmbase + - (info->txb_ptr - PPP508_MB_VECT)); - card->u.p.txbuf_last = (ppp_buf_ctl_t *) card->u.p.txbuf_base + - (info->txb_num - 1); - card->u.p.rxbuf_base = (void *) (card->hw.dpmbase + - (info->rxb_ptr - PPP508_MB_VECT)); - card->u.p.rxbuf_last = (ppp_buf_ctl_t *) card->u.p.rxbuf_base + - (info->rxb_num - 1); - card->u.p.rx_base = info->rxb_base; - card->u.p.rx_top = info->rxb_end; + + info = (void*)(card->hw.dpmbase + PPP508_BUF_OFFS); + + card->u.p.txbuf_base = (void*)(card->hw.dpmbase + + (info->txb_ptr - PPP508_MB_VECT)); + + card->u.p.txbuf_last = (ppp_buf_ctl_t*)card->u.p.txbuf_base + + (info->txb_num - 1); + + card->u.p.rxbuf_base = (void*)(card->hw.dpmbase + + (info->rxb_ptr - PPP508_MB_VECT)); + + card->u.p.rxbuf_last = (ppp_buf_ctl_t*)card->u.p.rxbuf_base + + (info->rxb_num - 1); } + + card->u.p.rx_base = info->rxb_base; + card->u.p.rx_top = info->rxb_end; + card->u.p.txbuf = card->u.p.txbuf_base; card->rxmb = card->u.p.rxbuf_base; + +} + +/*============================================================================= + * Read Connection Information (ie for Remote IP address assginment). + * Called when ppp interface connected. + */ +static int read_info( sdla_t *card ) +{ + struct net_device *dev = card->wandev.dev; + ppp_private_area_t *ppp_priv_area = dev->priv; + int err; + struct ifreq if_info; + struct sockaddr_in *if_data1, *if_data2; + mm_segment_t fs; + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + fs = get_fs(); + set_fs(get_ds()); /* get user space block */ + + + /* Change the local and remote ip address of the interface. + * This will also add in the destination route. + */ + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = ppp_priv_area->ip_local; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + if_data2 = (struct sockaddr_in *)&if_info.ifr_dstaddr; + if_data2->sin_addr.s_addr = ppp_priv_area->ip_remote; + if_data2->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFDSTADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + + if (err) { + printk (KERN_INFO "%s: Adding of route failed:\n", + card->devname); + printk (KERN_INFO "%s: Local : %s\n", + card->devname,in_ntoa(ppp_priv_area->ip_local)); + printk (KERN_INFO "%s: Remote: %s\n", + card->devname,in_ntoa(ppp_priv_area->ip_remote)); + } + return err; +} + +/*============================================================================= + * Remove Dynamic Route. + * Called when ppp interface disconnected. + */ + +static int remove_route( sdla_t *card ) +{ + + struct net_device *dev = card->wandev.dev; + long ip_addr; + int err; + + mm_segment_t fs; + struct ifreq if_info; + struct sockaddr_in *if_data1; + struct in_device *in_dev = dev->ip_ptr; + struct in_ifaddr *ifa = in_dev->ifa_list; + + + ip_addr = ifa->ifa_local; + + /* Set Local and remote addresses */ + memset(&if_info, 0, sizeof(if_info)); + strcpy(if_info.ifr_name, dev->name); + + + fs = get_fs(); + set_fs(get_ds()); /* get user space block */ + + + /* Change the local ip address of the interface to 0. + * This will also delete the destination route. + */ + if_data1 = (struct sockaddr_in *)&if_info.ifr_addr; + if_data1->sin_addr.s_addr = 0; + if_data1->sin_family = AF_INET; + err = devinet_ioctl( SIOCSIFADDR, &if_info ); + + set_fs(fs); /* restore old block */ + + + if (err) { + printk (KERN_INFO "%s: Deleting dynamic route failed %d!\n", + card->devname, err); + return err; + }else + printk (KERN_INFO "%s: PPP Deleting dynamic route %s successfuly\n", + card->devname, in_ntoa(ip_addr)); + + + return 0; } /*============================================================================= * Perform the Interrupt Test by running the READ_CODE_VERSION command MAX_INTR * _TEST_COUNTER times. */ - -static int intr_test(sdla_t * card) +static int intr_test( sdla_t *card ) { ppp_mbox_t *mb = card->mbox; - int err, i; - /* The critical flag is unset because during initialization (if_open) + int err,i; + + /* The critical flag is unset because during intialization (if_open) * we want the interrupts to be enabled so that when the wpp_isr is * called it does not exit due to critical flag set. - */ + */ + card->wandev.critical = 0; - err = ppp_set_intr_mode(card, 0x08); - if (err == CMD_OK) { - for (i = 0; i < MAX_INTR_TEST_COUNTER; i++) { + + err = ppp_set_intr_mode( card, 0x08 ); + + if (err == CMD_OK) { + + for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) { /* Run command READ_CODE_VERSION */ memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); - mb->cmd.length = 0; - mb->cmd.command = 0x10; + mb->cmd.length = 0; + mb->cmd.command = PPP_READ_CODE_VERSION; err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; - if (err != CMD_OK) + if (err != CMD_OK) ppp_error(card, err, mb); } - } else - return err; - err = ppp_set_intr_mode(card, 0); - if (err != CMD_OK) + } + else return err; + + err = ppp_set_intr_mode( card, 0 ); + if (err != CMD_OK) return err; + card->wandev.critical = 1; return 0; } @@ -2222,40 +2796,140 @@ static int intr_test(sdla_t * card) /*============================================================================== * Determine what type of UDP call it is. DRVSTATS or PTPIPEAB ? */ - -static int udp_pkt_type(struct sk_buff *skb, sdla_t * card) +static int udp_pkt_type( struct sk_buff *skb, sdla_t *card ) { unsigned char *sendpacket; - unsigned char buf2[5]; + unsigned char buf2[5]; + //FIXME: Use the structure + ppp_udp_pkt_t *ppp_udp_pkt = (ppp_udp_pkt_t *)skb->data; + sendpacket = skb->data; memcpy(&buf2, &card->wandev.udp_port, 2); - if (sendpacket[0] == 0x45 && /* IP packet */ - sendpacket[9] == 0x11 && /* UDP packet */ - sendpacket[22] == buf2[1] && /* UDP Port */ - sendpacket[23] == buf2[0] && - sendpacket[36] == 0x01) { - if (sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ - sendpacket[29] == 0x54 && - sendpacket[30] == 0x50 && - sendpacket[31] == 0x49 && - sendpacket[32] == 0x50 && - sendpacket[33] == 0x45 && - sendpacket[34] == 0x41 && - sendpacket[35] == 0x42) { + + if( ppp_udp_pkt->ip_pkt.ver_inet_hdr_length == 0x45 && /* IP packet */ + sendpacket[9] == 0x11 && /* UDP packet */ + sendpacket[22] == buf2[1] && /* UDP Port */ + sendpacket[23] == buf2[0] && + sendpacket[36] == 0x01 ) { + + if ( sendpacket[28] == 0x50 && /* PTPIPEAB: Signature */ + sendpacket[29] == 0x54 && + sendpacket[30] == 0x50 && + sendpacket[31] == 0x49 && + sendpacket[32] == 0x50 && + sendpacket[33] == 0x45 && + sendpacket[34] == 0x41 && + sendpacket[35] == 0x42 ){ + return UDP_PTPIPE_TYPE; - } else if (sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ - sendpacket[29] == 0x52 && - sendpacket[30] == 0x56 && - sendpacket[31] == 0x53 && - sendpacket[32] == 0x54 && - sendpacket[33] == 0x41 && - sendpacket[34] == 0x54 && - sendpacket[35] == 0x53) { + + } else if(sendpacket[28] == 0x44 && /* DRVSTATS: Signature */ + sendpacket[29] == 0x52 && + sendpacket[30] == 0x56 && + sendpacket[31] == 0x53 && + sendpacket[32] == 0x54 && + sendpacket[33] == 0x41 && + sendpacket[34] == 0x54 && + sendpacket[35] == 0x53 ){ + return UDP_DRVSTATS_TYPE; + } else return UDP_INVALID_TYPE; + } else return UDP_INVALID_TYPE; + +} + +/*============================================================================ + * Check to see if the packet to be transmitted contains a broadcast or + * multicast source IP address. + */ + +static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev, + struct sk_buff *skb) +{ + u32 src_ip_addr; + u32 broadcast_ip_addr = 0; + struct in_device *in_dev; + /* read the IP source address from the outgoing packet */ + src_ip_addr = *(u32 *)(skb->data + 12); + + /* read the IP broadcast address for the device */ + in_dev = dev->ip_ptr; + if(in_dev != NULL) { + struct in_ifaddr *ifa= in_dev->ifa_list; + if(ifa != NULL) + broadcast_ip_addr = ifa->ifa_broadcast; + else + return 0; + } + + /* check if the IP Source Address is a Broadcast address */ + if((dev->flags & IFF_BROADCAST) && (src_ip_addr == broadcast_ip_addr)) { + printk(KERN_INFO "%s: Broadcast Source Address silently discarded\n", + card->devname); + dev_kfree_skb(skb); + ++card->wandev.stats.tx_dropped; + return 1; + } + + /* check if the IP Source Address is a Multicast address */ + if((ntohl(src_ip_addr) >= 0xE0000001) && + (ntohl(src_ip_addr) <= 0xFFFFFFFE)) { + printk(KERN_INFO "%s: Multicast Source Address silently discarded\n", + card->devname); + dev_kfree_skb(skb); + ++card->wandev.stats.tx_dropped; + return 1; + } + + return 0; +} + +void s508_lock (sdla_t *card, unsigned long *smp_flags) +{ +#ifdef __SMP__ + spin_lock_irqsave(&card->lock, *smp_flags); +#else + disable_irq(card->hw.irq); +#endif +} + +void s508_unlock (sdla_t *card, unsigned long *smp_flags) +{ +#ifdef __SMP__ + spin_unlock_irqrestore(&card->lock, *smp_flags); +#else + enable_irq(card->hw.irq); +#endif +} + +static int read_connection_info (sdla_t *card) +{ + ppp_mbox_t *mb = card->mbox; + struct net_device *dev = card->wandev.dev; + ppp_private_area_t *ppp_priv_area = dev->priv; + ppp508_connect_info_t *ppp508_connect_info; + int err; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.length = 0; + mb->cmd.command = PPP_GET_CONNECTION_INFO; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + + if (err != CMD_OK) { + ppp_error(card, err, mb); + } + else { + ppp508_connect_info = (ppp508_connect_info_t *)mb->data; + + ppp_priv_area->ip_remote = ppp508_connect_info->ip_remote; + ppp_priv_area->ip_local = ppp508_connect_info->ip_local; + } + + return err; } /****** End *****************************************************************/ diff --git a/drivers/net/wan/sdladrv.c b/drivers/net/wan/sdladrv.c index 5e1f6b99e..06e86de82 100644 --- a/drivers/net/wan/sdladrv.c +++ b/drivers/net/wan/sdladrv.c @@ -4,17 +4,18 @@ * This module is a library of common hardware-specific functions * used by all Sangoma drivers. * -* Author: Gene Kozin <genek@compuserve.com> -* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> +* Author: Gideon Hack * -* Copyright: (c) 1995-1996 Sangoma Technologies Inc. +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. * * 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 the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* May 19, 1999 Arnaldo Melo wanpipe_init belongs to sdlamain.c +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Updates for Linux 2.2.X kernels. +* Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels * Dec 20, 1996 Gene Kozin Version 3.0.0. Complete overhaul. * Jul 12, 1996 Gene Kozin Changes for Linux 2.0 compatibility. * Jun 12, 1996 Gene Kozin Added support for S503 card. @@ -83,6 +84,8 @@ #if defined(_LINUX_) /****** Linux *******************************/ +#include <linux/config.h> +#include <linux/version.h> #include <linux/kernel.h> /* printk(), and other useful stuff */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ @@ -91,12 +94,18 @@ #include <linux/sched.h> /* for jiffies, HZ, etc. */ #include <linux/sdladrv.h> /* API definitions */ #include <linux/sdlasfm.h> /* SDLA firmware module definitions */ +#include <linux/sdlapci.h> /* SDLA PCI hardware definitions */ +#include <linux/pci.h> /* PCI defines and function prototypes */ #include <asm/io.h> /* for inb(), outb(), etc. */ + #define _INB(port) (inb(port)) #define _OUTB(port, byte) (outb((byte),(port))) #define SYSTEM_TICK jiffies +#include <linux/init.h> + #elif defined(_SCO_UNIX_) /****** SCO Unix ****************************/ + #if !defined(INKERNEL) #error This code MUST be compiled in kernel mode! #endif @@ -136,6 +145,11 @@ #define S503_MINMEM 0x8000L #define S507_MINMEM 0x20000L #define S508_MINMEM 0x20000L +#define NO_PORT -1 + + + + /****** Function Prototypes *************************************************/ @@ -159,14 +173,18 @@ static int init_s502e (sdlahw_t* hw); static int init_s503 (sdlahw_t* hw); static int init_s507 (sdlahw_t* hw); static int init_s508 (sdlahw_t* hw); - + static int detect_s502a (int port); static int detect_s502e (int port); static int detect_s503 (int port); static int detect_s507 (int port); static int detect_s508 (int port); +static int detect_s514 (sdlahw_t* hw); +static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card); /* Miscellaneous functions */ +static void peek_by_4 (unsigned long src, void* buf, unsigned len); +static void poke_by_4 (unsigned long dest, void* buf, unsigned len); static int calibrate_delay (int mks); static int get_option_index (unsigned* optlist, unsigned optval); static unsigned check_memregion (void* ptr, unsigned len); @@ -180,7 +198,7 @@ static unsigned short checksum (unsigned char* buf, unsigned len); /* private data */ static char modname[] = "sdladrv"; static char fullname[] = "SDLA Support Module"; -static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; static unsigned exec_idle; /* Hardware configuration options. @@ -289,6 +307,9 @@ static unsigned char s507_irqmask[] = #ifdef MODULE int init_module (void) +#else +__initfunc(int wanpipe_init(void)) +#endif { printk(KERN_INFO "%s v%u.%u %s\n", fullname, MOD_VERSION, MOD_RELEASE, copyright); @@ -299,6 +320,7 @@ int init_module (void) return 0; } +#ifdef MODULE /*============================================================================ * Module 'remove' entry point. * o release all remaining system resources @@ -321,7 +343,7 @@ void cleanup_module (void) * Return: 0 ok. * < 0 error */ - + EXPORT_SYMBOL(sdla_setup); int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len) @@ -329,118 +351,123 @@ int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len) unsigned* irq_opt = NULL; /* IRQ options */ unsigned* dpmbase_opt = NULL; /* DPM window base options */ unsigned* pclk_opt = NULL; /* CPU clock rate options */ - int err; + int err=0; - if (sdla_detect(hw)) - { - printk(KERN_ERR "%s: adapter S%04u not found at port 0x%X!\n", - modname, hw->type, hw->port) - ; + if (sdla_detect(hw)) { + if(hw->type != SDLA_S514) + printk(KERN_ERR "%s: no SDLA card found at port 0x%X\n", + modname, hw->port); return -EINVAL; } - printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n", - modname, hw->type, hw->port) - ; - - hw->dpmsize = SDLA_WINDOWSIZE; - switch (hw->type) - { - case SDLA_S502A: - hw->io_range = S502A_IORANGE; - irq_opt = s502a_irq_options; - dpmbase_opt = s502a_dpmbase_options; - pclk_opt = s502a_pclk_options; - break; - - case SDLA_S502E: - hw->io_range = S502E_IORANGE; - irq_opt = s502e_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s502e_pclk_options; - break; - - case SDLA_S503: - hw->io_range = S503_IORANGE; - irq_opt = s503_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s503_pclk_options; - break; - - case SDLA_S507: - hw->io_range = S507_IORANGE; - irq_opt = s508_irq_options; - dpmbase_opt = s507_dpmbase_options; - pclk_opt = s507_pclk_options; - break; - - case SDLA_S508: - hw->io_range = S508_IORANGE; - irq_opt = s508_irq_options; - dpmbase_opt = s508_dpmbase_options; - pclk_opt = s508_pclk_options; - break; - } - - /* Verify IRQ configuration options */ - if (!get_option_index(irq_opt, hw->irq)) - { - printk(KERN_ERR "%s: IRQ %d is illegal!\n", - modname, hw->irq) - ; - return -EINVAL; - } - /* Verify CPU clock rate configuration options */ - if (hw->pclk == 0) - hw->pclk = pclk_opt[1] /* use default */ - ; - else if (!get_option_index(pclk_opt, hw->pclk)) - { - printk(KERN_ERR "%s: CPU clock %u is illegal!\n", - modname, hw->pclk) - ; - return -EINVAL; - } - printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n", - modname, hw->pclk) - ; - - /* Setup adapter dual-port memory window and test memory */ - if (hw->dpmbase == 0) - { - err = sdla_autodpm(hw); - if (err) - { - printk(KERN_ERR + if(hw->type != SDLA_S514) { + printk(KERN_INFO "%s: found S%04u card at port 0x%X.\n", + modname, hw->type, hw->port); + + hw->dpmsize = SDLA_WINDOWSIZE; + switch (hw->type) { + case SDLA_S502A: + hw->io_range = S502A_IORANGE; + irq_opt = s502a_irq_options; + dpmbase_opt = s502a_dpmbase_options; + pclk_opt = s502a_pclk_options; + break; + + case SDLA_S502E: + hw->io_range = S502E_IORANGE; + irq_opt = s502e_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s502e_pclk_options; + break; + + case SDLA_S503: + hw->io_range = S503_IORANGE; + irq_opt = s503_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s503_pclk_options; + break; + + case SDLA_S507: + hw->io_range = S507_IORANGE; + irq_opt = s508_irq_options; + dpmbase_opt = s507_dpmbase_options; + pclk_opt = s507_pclk_options; + break; + + case SDLA_S508: + hw->io_range = S508_IORANGE; + irq_opt = s508_irq_options; + dpmbase_opt = s508_dpmbase_options; + pclk_opt = s508_pclk_options; + break; + } + + /* Verify IRQ configuration options */ + if (!get_option_index(irq_opt, hw->irq)) { + printk(KERN_ERR "%s: IRQ %d is illegal!\n", + modname, hw->irq); + return -EINVAL; + } + + /* Verify CPU clock rate configuration options */ + if (hw->pclk == 0) + hw->pclk = pclk_opt[1]; /* use default */ + + else if (!get_option_index(pclk_opt, hw->pclk)) { + printk(KERN_ERR "%s: CPU clock %u is illegal!\n", + modname, hw->pclk); + return -EINVAL; + } + printk(KERN_INFO "%s: assuming CPU clock rate of %u kHz.\n", + modname, hw->pclk); + + /* Setup adapter dual-port memory window and test memory */ + if (hw->dpmbase == 0) { + err = sdla_autodpm(hw); + if (err) { + printk(KERN_ERR "%s: can't find available memory region!\n", - modname) - ; - return err; + modname); + return err; + } + } + else if (!get_option_index(dpmbase_opt, + virt_to_phys(hw->dpmbase))) { + printk(KERN_ERR + "%s: memory address 0x%lX is illegal!\n", + modname, virt_to_phys(hw->dpmbase)); + return -EINVAL; + } + else if (sdla_setdpm(hw)) { + printk(KERN_ERR + "%s: 8K memory region at 0x%lX is not available!\n", + modname, virt_to_phys(hw->dpmbase)); + return -EINVAL; + } + printk(KERN_INFO + "%s: dual-port memory window is set at 0x%lX.\n", + modname, virt_to_phys(hw->dpmbase)); + } + + else { + hw->memory = test_memregion((void*)hw->dpmbase, + MAX_SIZEOF_S514_MEMORY); + if(hw->memory < (256 * 1024)) { + printk(KERN_ERR + "%s: error in testing S514 memory (0x%lX)\n", + modname, hw->memory); + sdla_down(hw); + return -EINVAL; } } - else if (!get_option_index(dpmbase_opt, virt_to_phys(hw->dpmbase))) - { - printk(KERN_ERR "%s: memory address 0x%lX is illegal!\n", - modname, virt_to_phys(hw->dpmbase)) - ; - return -EINVAL; - } - else if (sdla_setdpm(hw)) - { - printk(KERN_ERR - "%s: 8K memory region at 0x%lX is not available!\n", - modname, virt_to_phys(hw->dpmbase)); - return -EINVAL; - } - printk(KERN_INFO "%s: dual-port memory window is set at 0x%lX.\n", - modname, virt_to_phys(hw->dpmbase)); - - printk(KERN_INFO "%s: found %luK bytes of on-board memory.\n", + + printk(KERN_INFO "%s: found %luK bytes of on-board memory\n", modname, hw->memory / 1024); /* Load firmware. If loader fails then shut down adapter */ err = sdla_load(hw, sfm, len); if (err) sdla_down(hw); /* shutdown adapter */ + return err; } @@ -454,11 +481,13 @@ int sdla_down (sdlahw_t* hw) { unsigned port = hw->port; int i; + unsigned char CPU_no; + u32 int_config, int_status; - if (!port) return -EFAULT; + if(!port && (hw->type != SDLA_S514)) + return -EFAULT; - switch (hw->type) - { + switch (hw->type) { case SDLA_S502A: _OUTB(port, 0x08); /* halt CPU */ _OUTB(port, 0x08); @@ -483,6 +512,30 @@ int sdla_down (sdlahw_t* hw) hw->regs[0] = 0; break; + case SDLA_S514: + /* halt the adapter */ + *(char *)hw->vector = S514_CPU_HALT; + CPU_no = hw->S514_cpu_no[0]; + + /* disable the PCI IRQ and disable memory access */ + pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config); + int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B; + pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config); + read_S514_int_stat(hw, &int_status); + S514_intack(hw, int_status); + if(CPU_no == S514_CPU_A) + pci_write_config_dword(hw->pci_dev, PCI_MAP0_DWORD, + PCI_CPU_A_MEM_DISABLE); + else + pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD, + PCI_CPU_B_MEM_DISABLE); + + /* free up the allocated virtual memory */ + iounmap((void *)hw->dpmbase); + iounmap((void *)hw->vector); + break; + + default: return -EINVAL; } @@ -500,12 +553,10 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr) unsigned port = hw->port; register int tmp; - switch (hw->type) - { + switch (hw->type) { case SDLA_S502A: case SDLA_S502E: - if (addr < S502_MAXMEM) /* verify parameter */ - { + if (addr < S502_MAXMEM) { /* verify parameter */ tmp = addr >> 13; /* convert to register mask */ _OUTB(port + 2, tmp); hw->regs[2] = tmp; @@ -514,8 +565,7 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr) break; case SDLA_S503: - if (addr < S503_MAXMEM) /* verify parameter */ - { + if (addr < S503_MAXMEM) { /* verify parameter */ tmp = (hw->regs[0] & 0x8F) | ((addr >> 9) & 0x70); _OUTB(port, tmp); hw->regs[0] = tmp; @@ -524,11 +574,9 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr) break; case SDLA_S507: - if (addr < S507_MAXMEM) - { + if (addr < S507_MAXMEM) { if (!(_INB(port) & 0x02)) - return -EIO - ; + return -EIO; tmp = addr >> 13; /* convert to register mask */ _OUTB(port + 2, tmp); hw->regs[2] = tmp; @@ -537,8 +585,7 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr) break; case SDLA_S508: - if (addr < S508_MAXMEM) - { + if (addr < S508_MAXMEM) { tmp = addr >> 13; /* convert to register mask */ _OUTB(port + 2, tmp); hw->regs[2] = tmp; @@ -546,7 +593,10 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr) else return -EINVAL; break; - default: + case SDLA_S514: + return 0; + + default: return -EINVAL; } hw->vector = addr & 0xFFFFE000L; @@ -556,7 +606,7 @@ int sdla_mapmem (sdlahw_t* hw, unsigned long addr) /*============================================================================ * Enable interrupt generation. */ - + EXPORT_SYMBOL(sdla_inten); int sdla_inten (sdlahw_t* hw) @@ -564,14 +614,12 @@ int sdla_inten (sdlahw_t* hw) unsigned port = hw->port; int tmp, i; - switch (hw->type) - { + switch (hw->type) { case SDLA_S502E: /* Note thar interrupt control operations on S502E are allowed * only if CPU is enabled (bit 0 of status register is set). */ - if (_INB(port) & 0x01) - { + if (_INB(port) & 0x01) { _OUTB(port, 0x02); /* bit1 = 1, bit2 = 0 */ _OUTB(port, 0x06); /* bit1 = 1, bit2 = 1 */ hw->regs[0] = 0x06; @@ -585,8 +633,7 @@ int sdla_inten (sdlahw_t* hw) hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (!(_INB(port) & 0x02)) /* verify */ - return -EIO - ; + return -EIO; break; case SDLA_S508: @@ -595,14 +642,16 @@ int sdla_inten (sdlahw_t* hw) hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (!(_INB(port + 1) & 0x10)) /* verify */ - return -EIO - ; + return -EIO; break; case SDLA_S502A: case SDLA_S507: break; + case SDLA_S514: + break; + default: return -EINVAL; @@ -621,8 +670,7 @@ int sdla_intde (sdlahw_t* hw) unsigned port = hw->port; int tmp, i; - switch (hw->type) - { + switch (hw->type) { case SDLA_S502E: /* Notes: * 1) interrupt control operations are allowed only if CPU is @@ -631,8 +679,7 @@ int sdla_intde (sdlahw_t* hw) * causes IRQ line go high, therefore we are going to use * 0x04 instead: lower it to inhibit interrupts to PC. */ - if (_INB(port) & 0x01) - { + if (_INB(port) & 0x01) { _OUTB(port, hw->regs[0] & ~0x04); hw->regs[0] &= ~0x04; } @@ -645,8 +692,7 @@ int sdla_intde (sdlahw_t* hw) hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) & 0x02) /* verify */ - return -EIO - ; + return -EIO; break; case SDLA_S508: @@ -655,8 +701,7 @@ int sdla_intde (sdlahw_t* hw) hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) & 0x10) /* verify */ - return -EIO - ; + return -EIO; break; case SDLA_S502A: @@ -680,16 +725,14 @@ int sdla_intack (sdlahw_t* hw) unsigned port = hw->port; int tmp; - switch (hw->type) - { + switch (hw->type) { case SDLA_S502E: /* To acknoledge hardware interrupt we have to toggle bit 3 of * control register: \_/ * Note that interrupt control operations on S502E are allowed * only if CPU is enabled (bit 1 of status register is set). */ - if (_INB(port) & 0x01) - { + if (_INB(port) & 0x01) { tmp = hw->regs[0] & ~0x04; _OUTB(port, tmp); tmp |= 0x04; @@ -700,8 +743,7 @@ int sdla_intack (sdlahw_t* hw) break; case SDLA_S503: - if (_INB(port) & 0x04) - { + if (_INB(port) & 0x04) { tmp = hw->regs[0] & ~0x08; _OUTB(port, tmp); tmp |= 0x08; @@ -721,6 +763,31 @@ int sdla_intack (sdlahw_t* hw) return 0; } + +/*============================================================================ + * Acknowledge S514 hardware interrupt. + */ + +EXPORT_SYMBOL(S514_intack); + +void S514_intack (sdlahw_t* hw, u32 int_status) +{ + pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); +} + + +/*============================================================================ + * Read the S514 hardware interrupt status. + */ + +EXPORT_SYMBOL(read_S514_int_stat); + +void read_S514_int_stat (sdlahw_t* hw, u32* int_status) +{ + pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status); +} + + /*============================================================================ * Generate an interrupt to adapter's CPU. */ @@ -731,11 +798,9 @@ int sdla_intr (sdlahw_t* hw) { unsigned port = hw->port; - switch (hw->type) - { + switch (hw->type) { case SDLA_S502A: - if (!(_INB(port) & 0x40)) - { + if (!(_INB(port) & 0x40)) { _OUTB(port, 0x10); /* issue NMI to CPU */ hw->regs[0] = 0x10; } @@ -743,16 +808,14 @@ int sdla_intr (sdlahw_t* hw) break; case SDLA_S507: - if ((_INB(port) & 0x06) == 0x06) - { + if ((_INB(port) & 0x06) == 0x06) { _OUTB(port + 3, 0); } else return -EIO; break; case SDLA_S508: - if (_INB(port + 1) & 0x02) - { + if (_INB(port + 1) & 0x02) { _OUTB(port, 0x08); } else return -EIO; @@ -781,14 +844,19 @@ int sdla_exec (void* opflag) unsigned long tstop; int nloops; - if (*flag) return 0; /* ???? */ + if(readb(flag) != 0x00) { + printk(KERN_INFO + "WANPIPE: opp flag set on entry to sdla_exec\n"); + return 0; + } + + writeb(0x01, flag); - *flag = 1; tstop = SYSTEM_TICK + EXEC_TIMEOUT; - for (nloops = 1; *flag; ++nloops) - { + + for (nloops = 1; (readb(flag) == 0x01); ++ nloops) { unsigned delay = exec_idle; - while (--delay); /* delay */ + while (-- delay); /* delay */ if (SYSTEM_TICK > tstop) return 0; /* time is up! */ } return nloops; @@ -803,39 +871,79 @@ int sdla_exec (void* opflag) * This function is not atomic, so caller must disable interrupt if * interrupt routines are accessing adapter shared memory. */ - + EXPORT_SYMBOL(sdla_peek); int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) { - unsigned long oldvec = hw->vector; - unsigned winsize = hw->dpmsize; - unsigned curpos, curlen; /* current offset and block size */ - unsigned long curvec; /* current DPM window vector */ - int err = 0; if (addr + len > hw->memory) /* verify arguments */ - return -EINVAL - ; - while (len && !err) - { - curpos = addr % winsize; /* current window offset */ - curvec = addr - curpos; /* current window vector */ - curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len; - - /* Relocate window and copy block of data */ - err = sdla_mapmem(hw, curvec); - memcpy(buf, (void *)((u8 *)hw->dpmbase + curpos), curlen); - addr += curlen; - (char*)buf += curlen; - len -= curlen; + return -EINVAL; + + if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ + peek_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); + return 0; } - /* Restore DPM window position */ - sdla_mapmem(hw, oldvec); - return err; + else { /* copy data for the S508 adapter */ + unsigned long oldvec = hw->vector; + unsigned winsize = hw->dpmsize; + unsigned curpos, curlen; /* current offset and block size */ + unsigned long curvec; /* current DPM window vector */ + int err = 0; + + while (len && !err) { + curpos = addr % winsize; /* current window offset */ + curvec = addr - curpos; /* current window vector */ + curlen = (len > (winsize - curpos)) ? + (winsize - curpos) : len; + /* Relocate window and copy block of data */ + err = sdla_mapmem(hw, curvec); + peek_by_4 ((unsigned long)hw->dpmbase + curpos, buf, + curlen); + addr += curlen; + (char*)buf += curlen; + len -= curlen; + } + + /* Restore DPM window position */ + sdla_mapmem(hw, oldvec); + return err; + } } + +/*============================================================================ + * Read data from adapter's memory to a data buffer in 4-byte chunks. + * Note that we ensure that the SDLA memory address is on a 4-byte boundary + * before we begin moving the data in 4-byte chunks. +*/ + +static void peek_by_4 (unsigned long src, void* buf, unsigned len) +{ + + /* byte copy data until we get to a 4-byte boundary */ + while (len && (src & 0x03)) { + *(char *)buf ++ = readb(src ++); + len --; + } + + /* copy data in 4-byte chunks */ + while (len >= 4) { + *(unsigned long *)buf = readl(src); + buf += 4; + src += 4; + len -= 4; + } + + /* byte copy any remaining data */ + while (len) { + *(char *)buf ++ = readb(src ++); + len --; + } +} + + /*============================================================================ * Write Absolute Adapter Memory. * Transfer data from data buffer to adapter's memory. @@ -845,39 +953,79 @@ int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) * This function is not atomic, so caller must disable interrupt if * interrupt routines are accessing adapter shared memory. */ - + EXPORT_SYMBOL(sdla_poke); int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len) { - unsigned long oldvec = hw->vector; - unsigned winsize = hw->dpmsize; - unsigned curpos, curlen; /* current offset and block size */ - unsigned long curvec; /* current DPM window vector */ - int err = 0; if (addr + len > hw->memory) /* verify arguments */ - return -EINVAL - ; - while (len && !err) - { - curpos = addr % winsize; /* current window offset */ - curvec = addr - curpos; /* current window vector */ - curlen = (len > (winsize - curpos)) ? (winsize - curpos) : len; - - /* Relocate window and copy block of data */ - sdla_mapmem(hw, curvec); - memcpy((void*)((u8 *)hw->dpmbase + curpos), buf, curlen); - addr += curlen; - (char*)buf += curlen; - len -= curlen; + return -EINVAL; + + if(hw->type == SDLA_S514) { /* copy data for the S514 adapter */ + poke_by_4 ((unsigned long)hw->dpmbase + addr, buf, len); + return 0; } + + else { /* copy data for the S508 adapter */ + unsigned long oldvec = hw->vector; + unsigned winsize = hw->dpmsize; + unsigned curpos, curlen; /* current offset and block size */ + unsigned long curvec; /* current DPM window vector */ + int err = 0; + + while (len && !err) { + curpos = addr % winsize; /* current window offset */ + curvec = addr - curpos; /* current window vector */ + curlen = (len > (winsize - curpos)) ? + (winsize - curpos) : len; + /* Relocate window and copy block of data */ + sdla_mapmem(hw, curvec); + poke_by_4 ((unsigned long)hw->dpmbase + curpos, buf, + curlen); + addr += curlen; + (char*)buf += curlen; + len -= curlen; + } + + /* Restore DPM window position */ + sdla_mapmem(hw, oldvec); + return err; + } +} - /* Restore DPM window position */ - sdla_mapmem(hw, oldvec); - return err; + +/*============================================================================ + * Write from a data buffer to adapter's memory in 4-byte chunks. + * Note that we ensure that the SDLA memory address is on a 4-byte boundary + * before we begin moving the data in 4-byte chunks. +*/ + +static void poke_by_4 (unsigned long dest, void* buf, unsigned len) +{ + + /* byte copy data until we get to a 4-byte boundary */ + while (len && (dest & 0x03)) { + writeb (*(char *)buf ++, dest ++); + len --; + } + + /* copy data in 4-byte chunks */ + while (len >= 4) { + writel (*(unsigned long *)buf, dest); + dest += 4; + buf += 4; + len -= 4; + } + + /* byte copy any remaining data */ + while (len) { + writeb (*(char *)buf ++ , dest ++); + len --; + } } + #ifdef DONT_COMPIPLE_THIS #endif /* DONT_COMPIPLE_THIS */ @@ -898,11 +1046,10 @@ static int sdla_detect (sdlahw_t* hw) unsigned port = hw->port; int err = 0; - if (!port) - return -EFAULT - ; - switch (hw->type) - { + if (!port && (hw->type != SDLA_S514)) + return -EFAULT; + + switch (hw->type) { case SDLA_S502A: if (!detect_s502a(port)) err = -ENODEV; break; @@ -923,22 +1070,21 @@ static int sdla_detect (sdlahw_t* hw) if (!detect_s508(port)) err = -ENODEV; break; + case SDLA_S514: + if (!detect_s514(hw)) err = -ENODEV; + break; + default: if (detect_s502a(port)) - hw->type = SDLA_S502A - ; + hw->type = SDLA_S502A; else if (detect_s502e(port)) - hw->type = SDLA_S502E - ; + hw->type = SDLA_S502E; else if (detect_s503(port)) - hw->type = SDLA_S503 - ; + hw->type = SDLA_S503; else if (detect_s507(port)) - hw->type = SDLA_S507 - ; + hw->type = SDLA_S507; else if (detect_s508(port)) - hw->type = SDLA_S508 - ; + hw->type = SDLA_S508; else err = -ENODEV; } return err; @@ -953,8 +1099,7 @@ static int sdla_autodpm (sdlahw_t* hw) int i, err = -EINVAL; unsigned* opt; - switch (hw->type) - { + switch (hw->type) { case SDLA_S502A: opt = s502a_dpmbase_options; break; @@ -973,8 +1118,7 @@ static int sdla_autodpm (sdlahw_t* hw) return -EINVAL; } - for (i = opt[0]; i && err; --i) - { + for (i = opt[0]; i && err; --i) { hw->dpmbase = phys_to_virt(opt[i]); err = sdla_setdpm(hw); } @@ -997,8 +1141,7 @@ static int sdla_setdpm (sdlahw_t* hw) /* Shut down card and verify memory region */ sdla_down(hw); if (check_memregion(hw->dpmbase, hw->dpmsize)) - return -EINVAL - ; + return -EINVAL; /* Initialize adapter and test on-board memory segment by segment. * If memory size appears to be less than shared memory window size, @@ -1007,8 +1150,7 @@ static int sdla_setdpm (sdlahw_t* hw) err = sdla_init(hw); if (err) return err; - if (sdla_memtest(hw) < hw->dpmsize) /* less than window size */ - { + if (sdla_memtest(hw) < hw->dpmsize) { /* less than window size */ sdla_down(hw); return -EIO; } @@ -1023,32 +1165,28 @@ static int sdla_setdpm (sdlahw_t* hw) */ static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) { + int i; /* Verify firmware signature */ - if (strcmp(sfm->signature, SFM_SIGNATURE)) - { + if (strcmp(sfm->signature, SFM_SIGNATURE)) { printk(KERN_ERR "%s: not SDLA firmware!\n", - modname) - ; + modname); return -EINVAL; } /* Verify firmware module format version */ - if (sfm->version != SFM_VERSION) - { + if (sfm->version != SFM_VERSION) { printk(KERN_ERR "%s: firmware format %u rejected! Expecting %u.\n", - modname, sfm->version, SFM_VERSION) - ; + modname, sfm->version, SFM_VERSION); return -EINVAL; } /* Verify firmware module length and checksum */ if ((len - offsetof(sfm_t, image) != sfm->info.codesize) || (checksum((void*)&sfm->info, - sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) - { + sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) { printk(KERN_ERR "%s: firmware corrupted!\n", modname); return -EINVAL; } @@ -1056,8 +1194,11 @@ static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) /* Announce */ printk(KERN_INFO "%s: loading %s (ID=%u)...\n", modname, (sfm->descr[0] != '\0') ? sfm->descr : "unknown firmware", - sfm->info.codeid) - ; + sfm->info.codeid); + + if(hw->type == SDLA_S514) + printk(KERN_INFO "%s: loading S514 adapter, CPU %c\n", + modname, hw->S514_cpu_no[0]); /* Scan through the list of compatible adapters and make sure our * adapter type is listed. @@ -1066,49 +1207,41 @@ static int sdla_load (sdlahw_t* hw, sfm_t* sfm, unsigned len) (i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type); ++i) ; - if (i == SFM_MAX_SDLA) - { + if (i == SFM_MAX_SDLA) { printk(KERN_ERR "%s: firmware is not compatible with S%u!\n", - modname, hw->type) + modname, hw->type); ; return -EINVAL; } + /* Make sure there is enough on-board memory */ - if (hw->memory < sfm->info.memsize) - { + if (hw->memory < sfm->info.memsize) { printk(KERN_ERR "%s: firmware needs %lu bytes of on-board memory!\n", - modname, sfm->info.memsize) - ; + modname, sfm->info.memsize); return -EINVAL; } /* Move code onto adapter */ - if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) - { + if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) { printk(KERN_ERR "%s: failed to load code segment!\n", - modname) - ; + modname); return -EIO; } /* Prepare boot-time configuration data and kick-off CPU */ sdla_bootcfg(hw, &sfm->info); - if (sdla_start(hw, sfm->info.startoffs)) - { + if (sdla_start(hw, sfm->info.startoffs)) { printk(KERN_ERR "%s: Damn... Adapter won't start!\n", - modname) - ; + modname); return -EIO; } /* position DPM window over the mailbox and enable interrupts */ - if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) - { + if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) { printk(KERN_ERR "%s: adapter hardware failure!\n", - modname) - ; + modname); return -EIO; } hw->fwid = sfm->info.codeid; /* set firmware ID */ @@ -1123,10 +1256,9 @@ static int sdla_init (sdlahw_t* hw) int i; for (i = 0; i < SDLA_MAXIORANGE; ++i) - hw->regs[i] = 0 - ; - switch (hw->type) - { + hw->regs[i] = 0; + + switch (hw->type) { case SDLA_S502A: return init_s502a(hw); case SDLA_S502E: return init_s502e(hw); case SDLA_S503: return init_s503(hw); @@ -1169,23 +1301,28 @@ static int sdla_bootcfg (sdlahw_t* hw, sfm_info_t* sfminfo) if (!sfminfo->datasize) return 0; /* nothing to do */ if (sdla_mapmem(hw, sfminfo->dataoffs) != 0) - return -EIO - ; - data = (void*)((u8 *)hw->dpmbase + (sfminfo->dataoffs - hw->vector)); - memset(data, 0, sfminfo->datasize); + return -EIO; + + if(hw->type == SDLA_S514) + data = (void*)(hw->dpmbase + sfminfo->dataoffs); + else + data = (void*)((u8 *)hw->dpmbase + + (sfminfo->dataoffs - hw->vector)); + + memset_io (data, 0, sfminfo->datasize); - data[0x00] = make_config_byte(hw); - switch (sfminfo->codeid) - { + writeb (make_config_byte(hw), &data[0x00]); + + switch (sfminfo->codeid) { case SFID_X25_502: case SFID_X25_508: - data[0x01] = 3; /* T1 timer */ - data[0x03] = 10; /* N2 */ - data[0x06] = 7; /* HDLC window size */ - data[0x0B] = 1; /* DTE */ - data[0x0C] = 2; /* X.25 packet window size */ - *(short*)&data[0x0D] = 128; /* default X.25 data size */ - *(short*)&data[0x0F] = 128; /* maximum X.25 data size */ + writeb (3, &data[0x01]); /* T1 timer */ + writeb (10, &data[0x03]); /* N2 */ + writeb (7, &data[0x06]); /* HDLC window size */ + writeb (1, &data[0x0B]); /* DTE */ + writeb (2, &data[0x0C]); /* X.25 packet window size */ + writew (128, &data[0x0D]); /* default X.25 data size */ + writew (128, &data[0x0F]); /* maximum X.25 data size */ break; } return 0; @@ -1198,16 +1335,15 @@ static unsigned char make_config_byte (sdlahw_t* hw) { unsigned char byte = 0; - switch (hw->pclk) - { + switch (hw->pclk) { case 5000: byte = 0x01; break; case 7200: byte = 0x02; break; case 8000: byte = 0x03; break; case 10000: byte = 0x04; break; case 16000: byte = 0x05; break; } - switch (hw->type) - { + + switch (hw->type) { case SDLA_S502E: byte |= 0x80; break; case SDLA_S503: byte |= 0x40; break; } @@ -1227,10 +1363,9 @@ static int sdla_start (sdlahw_t* hw, unsigned addr) unsigned char *bootp; int err, tmp, i; - if (!port) return -EFAULT; + if (!port && (hw->type != SDLA_S514)) return -EFAULT; - switch (hw->type) - { + switch (hw->type) { case SDLA_S502A: bootp = hw->dpmbase; bootp += 0x66; @@ -1240,6 +1375,7 @@ static int sdla_start (sdlahw_t* hw, unsigned addr) case SDLA_S503: case SDLA_S507: case SDLA_S508: + case SDLA_S514: bootp = hw->dpmbase; break; @@ -1250,12 +1386,11 @@ static int sdla_start (sdlahw_t* hw, unsigned addr) err = sdla_mapmem(hw, 0); if (err) return err; - *bootp = 0xC3; /* Z80: 'jp' opcode */ - bootp++; - *((unsigned short*)(bootp)) = addr; + writeb (0xC3, bootp); /* Z80: 'jp' opcode */ + bootp ++; + writew (addr, bootp); - switch (hw->type) - { + switch (hw->type) { case SDLA_S502A: _OUTB(port, 0x10); /* issue NMI to CPU */ hw->regs[0] = 0x10; @@ -1265,8 +1400,7 @@ static int sdla_start (sdlahw_t* hw, unsigned addr) _OUTB(port + 3, 0x01); /* start CPU */ hw->regs[3] = 0x01; for (i = 0; i < SDLA_IODELAY; ++i); - if (_INB(port) & 0x01) /* verify */ - { + if (_INB(port) & 0x01) { /* verify */ /* * Enabling CPU changes functionality of the * control register, so we have to reset its @@ -1284,8 +1418,7 @@ static int sdla_start (sdlahw_t* hw, unsigned addr) hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); if (!(_INB(port) & 0x01)) /* verify */ - return -EIO - ; + return -EIO; break; case SDLA_S507: @@ -1294,8 +1427,7 @@ static int sdla_start (sdlahw_t* hw, unsigned addr) hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); if (!(_INB(port) & 0x04)) /* verify */ - return -EIO - ; + return -EIO; break; case SDLA_S508: @@ -1304,8 +1436,11 @@ static int sdla_start (sdlahw_t* hw, unsigned addr) hw->regs[0] = tmp; /* update mirror */ for (i = 0; i < SDLA_IODELAY; ++i); if (!(_INB(port + 1) & 0x02)) /* verify */ - return -EIO - ; + return -EIO; + break; + + case SDLA_S514: + writeb (S514_CPU_START, hw->vector); break; default: @@ -1323,20 +1458,18 @@ static int init_s502a (sdlahw_t* hw) int tmp, i; if (!detect_s502a(port)) - return -ENODEV - ; + return -ENODEV; + hw->regs[0] = 0x08; hw->regs[1] = 0xFF; /* Verify configuration options */ i = get_option_index(s502a_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) - return -EINVAL - ; + return -EINVAL; tmp = s502a_hmcr[i - 1]; - switch (hw->dpmsize) - { + switch (hw->dpmsize) { case 0x2000: tmp |= 0x01; break; @@ -1364,18 +1497,15 @@ static int init_s502e (sdlahw_t* hw) int tmp, i; if (!detect_s502e(port)) - return -ENODEV - ; + return -ENODEV; /* Verify configuration options */ i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) - return -EINVAL - ; + return -EINVAL; tmp = s502e_hmcr[i - 1]; - switch (hw->dpmsize) - { + switch (hw->dpmsize) { case 0x2000: tmp |= 0x01; break; @@ -1408,18 +1538,15 @@ static int init_s503 (sdlahw_t* hw) int tmp, i; if (!detect_s503(port)) - return -ENODEV - ; + return -ENODEV; /* Verify configuration options */ i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) - return -EINVAL - ; + return -EINVAL; tmp = s502e_hmcr[i - 1]; - switch (hw->dpmsize) - { + switch (hw->dpmsize) { case 0x2000: tmp |= 0x01; break; @@ -1450,18 +1577,15 @@ static int init_s507 (sdlahw_t* hw) int tmp, i; if (!detect_s507(port)) - return -ENODEV - ; + return -ENODEV; /* Verify configuration options */ i = get_option_index(s507_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) - return -EINVAL - ; + return -EINVAL; tmp = s507_hmcr[i - 1]; - switch (hw->dpmsize) - { + switch (hw->dpmsize) { case 0x2000: tmp |= 0x01; break; @@ -1478,8 +1602,7 @@ static int init_s507 (sdlahw_t* hw) hw->regs[0] = 0x01; for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (!(_INB(port) & 0x20)) - return -EIO - ; + return -EIO; /* Setup dual-port memory window */ _OUTB(port + 1, tmp); @@ -1487,8 +1610,7 @@ static int init_s507 (sdlahw_t* hw) /* Enable memory access */ tmp = hw->regs[0] | 0x04; - if (hw->irq) - { + if (hw->irq) { i = get_option_index(s508_irq_options, hw->irq); if (i) tmp |= s507_irqmask[i - 1]; } @@ -1507,14 +1629,12 @@ static int init_s508 (sdlahw_t* hw) int tmp, i; if (!detect_s508(port)) - return -ENODEV - ; + return -ENODEV; /* Verify configuration options */ i = get_option_index(s508_dpmbase_options, virt_to_phys(hw->dpmbase)); if (i == 0) - return -EINVAL - ; + return -EINVAL; /* Setup memory configuration */ tmp = s508_hmcr[i - 1]; @@ -1547,13 +1667,11 @@ static int detect_s502a (int port) int i, j; if (!get_option_index(s502_port_options, port)) - return 0 - ; - for (j = 1; j < SDLA_MAXIORANGE; ++j) - { + return 0; + + for (j = 1; j < SDLA_MAXIORANGE; ++j) { if (_INB(port + j) != 0xFF) - return 0 - ; + return 0; for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ } @@ -1562,18 +1680,15 @@ static int detect_s502a (int port) _OUTB(port, 0x08); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0x40) - return 0 - ; + return 0; _OUTB(port, 0x00); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0x40) - return 0 - ; + return 0; _OUTB(port, 0x04); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0x44) - return 0 - ; + return 0; /* Reset adapter */ _OUTB(port, 0x08); @@ -1600,26 +1715,21 @@ static int detect_s502e (int port) int i, j; if (!get_option_index(s502_port_options, port)) - return 0 - ; - for (j = 1; j < SDLA_MAXIORANGE; ++j) - { + return 0; + for (j = 1; j < SDLA_MAXIORANGE; ++j) { if (_INB(port + j) != 0xFF) - return 0 - ; + return 0; for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ } _OUTB(port + 3, 0); /* CPU control reg. */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0xF8) /* read status */ - return 0 - ; + return 0; _OUTB(port, 0x04); /* set bit 2 */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0xFC) /* verify */ - return 0 - ; + return 0; /* Reset adapter */ _OUTB(port, 0); @@ -1643,26 +1753,21 @@ static int detect_s503 (int port) int i, j; if (!get_option_index(s503_port_options, port)) - return 0 - ; - for (j = 1; j < SDLA_MAXIORANGE; ++j) - { + return 0; + for (j = 1; j < SDLA_MAXIORANGE; ++j) { if (_INB(port + j) != 0xFF) - return 0 - ; + return 0; for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ } _OUTB(port, 0); /* reset control reg.*/ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0xF0) /* read status */ - return 0 - ; + return 0; _OUTB(port, 0x04); /* set bit 2 */ for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if (_INB(port) != 0xF2) /* verify */ - return 0 - ; + return 0; /* Reset adapter */ _OUTB(port, 0); @@ -1686,27 +1791,22 @@ static int detect_s507 (int port) int tmp, i, j; if (!get_option_index(s508_port_options, port)) - return 0 - ; + return 0; tmp = _INB(port); - for (j = 1; j < S507_IORANGE; ++j) - { + for (j = 1; j < S507_IORANGE; ++j) { if (_INB(port + j) != tmp) - return 0 - ; + return 0; for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ } _OUTB(port, 0x00); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if ((_INB(port) & 0x7E) != 0x30) - return 0 - ; + return 0; _OUTB(port, 0x01); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if ((_INB(port) & 0x7E) != 0x32) - return 0 - ; + return 0; /* Reset adapter */ _OUTB(port, 0x00); @@ -1729,24 +1829,205 @@ static int detect_s508 (int port) int i; if (!get_option_index(s508_port_options, port)) - return 0 - ; + return 0; _OUTB(port, 0x00); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if ((_INB(port + 1) & 0x3F) != 0x00) - return 0 - ; + return 0; _OUTB(port, 0x10); for (i = 0; i < SDLA_IODELAY; ++i); /* delay */ if ((_INB(port + 1) & 0x3F) != 0x10) - return 0 - ; + return 0; /* Reset adapter */ _OUTB(port, 0x00); return 1; } +/*============================================================================ + * Detect s514 PCI adapter. + * Return 1 if detected o.k. or 0 if failed. + * Note: This test is destructive! Adapter will be left in shutdown + * state after the test. + */ +static int detect_s514 (sdlahw_t* hw) +{ + unsigned char CPU_no, slot_no; + int number_S514_cards = 0; + u32 S514_mem_base_addr = 0; + u32 ut_u32; + + struct pci_dev *pci_dev; + + +#ifdef CONFIG_PCI + if(!pci_present()) + { + printk(KERN_ERR "%s: PCI BIOS not present!\n", modname); + return 0; + } +#else + printk(KERN_ERR "%s: Linux not compiled for PCI usage!\n", modname); + return 0; +#endif + + /* + The 'setup()' procedure in 'sdlamain.c' passes the CPU number and the + slot number defined in 'router.conf' via the 'port' definition. + */ + CPU_no = hw->S514_cpu_no[0]; + slot_no = hw->S514_slot_no; + + printk(KERN_INFO "%s: detecting S514 card, CPU %c, slot #%d\n", + modname, CPU_no, slot_no); + + /* check to see that CPU A or B has been selected in 'router.conf' */ + switch(CPU_no) { + case S514_CPU_A: + case S514_CPU_B: + break; + + default: + printk(KERN_ERR "%s: S514 CPU definition invalid.\n", + modname); + printk(KERN_ERR "Must be 'A' or 'B'\n"); + return 0; + } + + number_S514_cards = find_s514_adapter(hw, 0); + if(!number_S514_cards) + return 0; + + /* we are using a single S514 adapter with a slot of 0 so re-read the */ /* location of this adapter */ + if((number_S514_cards == 1) && !slot_no) { + number_S514_cards = find_s514_adapter(hw, 1); + if(!number_S514_cards) { + printk(KERN_ERR "%s: Error finding PCI card\n", + modname); + return 0; + } + } + + pci_dev = hw->pci_dev; + /* read the physical memory base address */ + S514_mem_base_addr = (CPU_no == S514_CPU_A) ? + (pci_dev->resource[1].start) : + (pci_dev->resource[2].start); + + printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n", + modname, S514_mem_base_addr); + if(!S514_mem_base_addr) { + if(CPU_no == S514_CPU_B) + printk(KERN_ERR "%s: CPU #B not present on the card\n", modname); + else + printk(KERN_ERR "%s: No PCI memory allocated to card\n", modname); + return 0; + } + + /* enable the PCI memory */ + pci_read_config_dword(pci_dev, + (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, + &ut_u32); + pci_write_config_dword(pci_dev, + (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD, + (ut_u32 | PCI_MEMORY_ENABLE)); + + /* check the IRQ allocated and enable IRQ usage */ + if(!(hw->irq = pci_dev->irq)) { + printk(KERN_ERR "%s: IRQ not allocated to S514 adapter\n", + modname); + return 0; + } + pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32); + ut_u32 |= (CPU_no == S514_CPU_A) ? + PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B; + pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32); + + printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n", + modname, hw->irq); + + /* map the physical PCI memory to virtual memory */ + (void *)hw->dpmbase = ioremap((unsigned long)S514_mem_base_addr, + (unsigned long)MAX_SIZEOF_S514_MEMORY); + /* map the physical control register memory to virtual memory */ + (void *)hw->vector = ioremap( + (unsigned long)(S514_mem_base_addr + S514_CTRL_REG_BYTE), + (unsigned long)16); + + if(!hw->dpmbase || !hw->vector) { + printk(KERN_ERR "%s: PCI virtual memory allocation failed\n", + modname); + return 0; + } + + /* halt the adapter */ + writeb (S514_CPU_HALT, hw->vector); + + return 1; +} + +/*============================================================================ + * Find the S514 PCI adapter in the PCI bus. + * Return the number of S514 adapters found (0 if no adapter found). + */ +static int find_s514_adapter(sdlahw_t* hw, char find_first_S514_card) +{ + unsigned char slot_no; + int number_S514_cards = 0; + char S514_found_in_slot = 0; + u16 PCI_subsys_vendor; + + struct pci_dev *pci_dev = NULL; + + slot_no = hw->S514_slot_no; + + while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev)) + != NULL) { + pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD, + &PCI_subsys_vendor); + if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR) + continue; + hw->pci_dev = pci_dev; + if(find_first_S514_card) + return(1); + number_S514_cards ++; + printk(KERN_INFO + "%s: S514 card found, slot #%d (devfn 0x%X)\n", + modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK), + pci_dev->devfn); + if(slot_no && (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == + slot_no)) { + S514_found_in_slot = 1; + break; + } + } + + /* if no S514 adapter has been found, then exit */ + if(!number_S514_cards) { + printk(KERN_ERR "%s: no S514 adapters found\n", modname); + return 0; + } + /* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */ + else if((number_S514_cards > 1) && !slot_no) { + printk(KERN_ERR "%s: More than one S514 adapter found\n", + modname); + printk(KERN_ERR "Define a PCI slot number for this adapter\n"); + return 0; + } + /* if the user has specified a slot number and the S514 adapter has */ + /* not been found in that slot, then exit */ + else if (slot_no && !S514_found_in_slot) { + printk(KERN_ERR + "%s: S514 card not found in specified slot #%d\n", + modname, slot_no); + return 0; + } + + return (number_S514_cards); +} + + + /******* Miscellaneous ******************************************************/ /*============================================================================ @@ -1772,8 +2053,8 @@ static int get_option_index (unsigned* optlist, unsigned optval) int i; for (i = 1; i <= optlist[0]; ++i) - if ( optlist[i] == optval) return i - ; + if ( optlist[i] == optval) + return i; return 0; } @@ -1785,15 +2066,14 @@ static unsigned check_memregion (void* ptr, unsigned len) { volatile unsigned char* p = ptr; - for (; len && (*p == 0xFF); --len, ++p) - { - *p = 0; /* attempt to write 0 */ - if (*p != 0xFF) /* still has to read 0xFF */ - { - *p = 0xFF; /* restore original value */ - break; /* not good */ - } - } + for (; len && (readb (p) == 0xFF); --len, ++p) { + writeb (0, p); /* attempt to write 0 */ + if (readb(p) != 0xFF) { /* still has to read 0xFF */ + writeb (0xFF, p);/* restore original value */ + break; /* not good */ + } + } + return len; } @@ -1808,28 +2088,28 @@ static unsigned test_memregion (void* ptr, unsigned len) unsigned len_w = len >> 1; /* region len in words */ unsigned i; + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + writew (0xAA55, w_ptr); + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - *w_ptr = 0xAA55 - ; - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - if (*w_ptr != 0xAA55) - { - len_w = i; - break; - } - ; - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - *w_ptr = 0x55AA - ; - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) - if (*w_ptr != 0x55AA) - { - len_w = i; - break; - } - ; - for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) *w_ptr = 0; - return len_w << 1; + if (readw (w_ptr) != 0xAA55) { + len_w = i; + break; + } + + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + writew (0x55AA, w_ptr); + + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + if (readw(w_ptr) != 0x55AA) { + len_w = i; + break; + } + + for (i = 0, w_ptr = ptr; i < len_w; ++i, ++w_ptr) + writew (0, w_ptr); + + return len_w << 1; } /*============================================================================ @@ -1840,10 +2120,8 @@ static unsigned short checksum (unsigned char* buf, unsigned len) unsigned short crc = 0; unsigned mask, flag; - for (; len; --len, ++buf) - { - for (mask = 0x80; mask; mask >>= 1) - { + for (; len; --len, ++buf) { + for (mask = 0x80; mask; mask >>= 1) { flag = (crc & 0x8000); crc <<= 1; crc |= ((*buf & mask) ? 1 : 0); diff --git a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c index 23b811fc9..3565954e1 100644 --- a/drivers/net/wan/sdlamain.c +++ b/drivers/net/wan/sdlamain.c @@ -1,18 +1,21 @@ /***************************************************************************** * sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module. * -* Author: Gene Kozin <genek@compuserve.com> -* Jaspreet Singh <jaspreet@sangoma.com> -* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> +* Author: Nenad Corbic <ncorbic@sangoma.com> +* Gideon Hack * -* Copyright: (c) 1995-1997 Sangoma Technologies Inc. +* Copyright: (c) 1995-1999 Sangoma Technologies Inc. * * 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 the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ -* May 19, 1999 Arnaldo Melo __init for wanpipe_init +* Sep 23, 1999 Nenad Corbic Added support for SMP +* Sep 13, 1999 Nenad Corbic Each port is treated as a separate device. +* Jun 02, 1999 Gideon Hack Added support for the S514 adapter. +* Updates for Linux 2.2.X kernels. +* Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel * Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1 * Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags(); * Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0 @@ -31,6 +34,7 @@ * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ +#include <linux/version.h> #include <linux/config.h> /* OS configuration options */ #include <linux/stddef.h> /* offsetof(), etc. */ #include <linux/errno.h> /* return codes */ @@ -44,8 +48,8 @@ #include <linux/wanpipe.h> /* WANPIPE common user API definitions */ #include <asm/uaccess.h> /* kernel <-> user copy */ #include <asm/io.h> /* phys_to_virt() */ -#include <linux/init.h> /* __init (when not using as a module) */ - +#include <linux/pci.h> +#include <linux/sdlapci.h> /****** Defines & Macros ****************************************************/ @@ -55,8 +59,8 @@ #define STATIC static #endif -#define DRV_VERSION 4 /* version number */ -#define DRV_RELEASE 1 /* release (minor version) number */ +#define DRV_VERSION 5 /* version number */ +#define DRV_RELEASE 0 /* release (minor version) number */ #define MAX_CARDS 8 /* max number of adapters */ #ifndef CONFIG_WANPIPE_CARDS /* configurable option */ @@ -66,9 +70,11 @@ #define CMD_OK 0 /* normal firmware return code */ #define CMD_TIMEOUT 0xFF /* firmware command timed out */ #define MAX_CMD_RETRY 10 /* max number of firmware retries */ - /****** Function Prototypes *************************************************/ +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + /* Module entry points */ int init_module (void); void cleanup_module (void); @@ -78,13 +84,14 @@ static int setup (wan_device_t* wandev, wandev_conf_t* conf); static int shutdown (wan_device_t* wandev); static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg); -/* IOCTL hanlers */ +/* IOCTL handlers */ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump); static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec); /* Miscellaneous functions */ STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs); STATIC void sdla_poll (void* data); +static void release_hw (sdla_t *card); /****** Global Data ********************************************************** * Note: All data must be explicitly initialized!!! @@ -93,7 +100,7 @@ STATIC void sdla_poll (void* data); /* private data */ static char drvname[] = "wanpipe"; static char fullname[] = "WANPIPE(tm) Multiprotocol Driver"; -static char copyright[] = "(c) 1995-1996 Sangoma Technologies Inc."; +static char copyright[] = "(c) 1995-1999 Sangoma Technologies Inc."; static int ncards = CONFIG_WANPIPE_CARDS; static int active = 0; /* number of active cards */ static sdla_t* card_array = NULL; /* adapter data space */ @@ -107,6 +114,7 @@ static struct tq_struct sdla_tq = NULL /* .data */ }; + /******* Kernel Loadable Module Entry Points ********************************/ /*============================================================================ @@ -125,30 +133,29 @@ static struct tq_struct sdla_tq = #ifdef MODULE int init_module (void) #else -int __init wanpipe_init(void) +int wanpipe_init2(void) #endif { int cnt, err = 0; printk(KERN_INFO "%s v%u.%u %s\n", - fullname, DRV_VERSION, DRV_RELEASE, copyright) - ; + fullname, DRV_VERSION, DRV_RELEASE, copyright); /* Verify number of cards and allocate adapter data space */ ncards = min(ncards, MAX_CARDS); ncards = max(ncards, 1); card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); if (card_array == NULL) - return -ENOMEM - ; + return -ENOMEM; + memset(card_array, 0, sizeof(sdla_t) * ncards); /* Register adapters with WAN router */ - for (cnt = 0; cnt < ncards; ++cnt) - { + for (cnt = 0; cnt < ncards; ++ cnt) { sdla_t* card = &card_array[cnt]; wan_device_t* wandev = &card->wandev; + card->next = NULL; sprintf(card->devname, "%s%d", drvname, cnt + 1); wandev->magic = ROUTER_MAGIC; wandev->name = card->devname; @@ -158,20 +165,18 @@ int __init wanpipe_init(void) wandev->shutdown = &shutdown; wandev->ioctl = &ioctl; err = register_wan_device(wandev); - if (err) - { + if (err) { printk(KERN_ERR "%s: %s registration failed with error %d!\n", - drvname, card->devname, err) - ; + drvname, card->devname, err); break; } } - if (cnt) + if (cnt){ ncards = cnt; /* adjust actual number of cards */ - else - { + }else { kfree(card_array); + printk(KERN_INFO "IN Init Module: NO Cards registered\n"); err = -ENODEV; } return err; @@ -187,8 +192,7 @@ void cleanup_module (void) { int i; - for (i = 0; i < ncards; ++i) - { + for (i = 0; i < ncards; ++i) { sdla_t* card = &card_array[i]; unregister_wan_device(card->devname); } @@ -200,7 +204,7 @@ void cleanup_module (void) /******* WAN Device Driver Entry Points *************************************/ /*============================================================================ - * Setup/confugure WAN link driver. + * Setup/configure WAN link driver. * o check adapter state * o make sure firmware is present in configuration * o make sure I/O port and IRQ are specified @@ -220,7 +224,8 @@ static int setup (wan_device_t* wandev, wandev_conf_t* conf) { sdla_t* card; int err = 0; - int irq; + int irq=0; + int i; /* Sanity checks */ if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)) @@ -230,80 +235,187 @@ static int setup (wan_device_t* wandev, wandev_conf_t* conf) if (wandev->state != WAN_UNCONFIGURED) return -EBUSY; /* already configured */ - if (!conf->data_size || (conf->data == NULL)) - { + printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name); + + /* Initialize the counters for each wandev + * Used for counting number of times new_if and + * del_if get called. + */ + wandev->del_if_cnt = 0; + wandev->new_if_cnt = 0; + wandev->config_id = conf->config_id; + + if (!conf->data_size || (conf->data == NULL)) { printk(KERN_ERR "%s: firmware not found in configuration data!\n", wandev->name); return -EINVAL; } - if (conf->ioport <= 0) - { - printk(KERN_ERR + + /* only check I/O port and IRQ if not an S514 adapter */ + if(!conf->S514_CPU_no[0]) { + + if (conf->ioport <= 0) { + printk(KERN_ERR "%s: can't configure without I/O port address!\n", wandev->name); - return -EINVAL; - } + return -EINVAL; + } - if (conf->irq <= 0) - { - printk(KERN_ERR "%s: can't configure without IRQ!\n", + if (conf->irq <= 0) { + printk(KERN_ERR "%s: can't configure without IRQ!\n", wandev->name); - return -EINVAL; + return -EINVAL; + } + + /* Check for already loaded card with the same IO port and IRQ + * If found, copy its hardware configuration and use its + * resources (i.e. piggybacking) + */ + if (!card->configured){ + for (i = 0; i < ncards; i ++) { + sdla_t *nxt_card = &card_array[i]; + if (nxt_card->hw.port == conf->ioport && + nxt_card != card && + conf->config_id == WANCONFIG_CHDLC && + nxt_card->wandev.config_id == WANCONFIG_CHDLC){ + irq = nxt_card->hw.irq; + memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); + nxt_card->next = card; + card->next = nxt_card; + card->wandev.piggyback = WANOPT_YES; + } + } + + + /* Make sure I/O port region is available */ + if (check_region(conf->ioport, SDLA_MAXIORANGE) && + !card->wandev.piggyback) { + printk(KERN_ERR + "%s: I/O region 0x%X - 0x%X is in use!\n", + wandev->name, conf->ioport, + conf->ioport + SDLA_MAXIORANGE); + return -EINVAL; + } + } } - /* Make sure I/O port region is available */ - if (check_region(conf->ioport, SDLA_MAXIORANGE)) - { - printk(KERN_ERR "%s: I/O region 0x%X - 0x%X is in use!\n", - wandev->name, conf->ioport, - conf->ioport + SDLA_MAXIORANGE); - return -EINVAL; + /* + For a S514 adapter, check for a possible configuration error in that + we are loading an adapter in the same slot as a previously loaded S514 + card. + */ + else { + if (!card->configured){ + for (i = 0; i < ncards; i ++) { + sdla_t* nxt_card = &card_array[i]; + if(nxt_card == card) + continue; + if((nxt_card->hw.type == SDLA_S514) && + (nxt_card->hw.S514_slot_no == conf->PCI_slot_no) && + (nxt_card->hw.S514_cpu_no[0] == conf->S514_CPU_no[0])&& + (conf->config_id == WANCONFIG_CHDLC)&& + (nxt_card->wandev.config_id == WANCONFIG_CHDLC)){ + + irq = nxt_card->hw.irq; + memcpy(&card->hw, &nxt_card->hw, sizeof(sdlahw_t)); + nxt_card->next = card; + card->next = nxt_card; + card->wandev.piggyback = WANOPT_YES; + } + } + } } - /* Allocate IRQ */ - irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ - if (request_irq(irq, sdla_isr, 0, wandev->name, card)) - { - printk(KERN_ERR "%s: can't reserve IRQ %d!\n", - wandev->name, irq); - return -EINVAL; - } + /* If the current card has already been configured + * or its a piggyback card, do not try to allocate + * resources. + */ + if (!card->wandev.piggyback && !card->configured){ + + /* Configure hardware, load firmware, etc. */ + memset(&card->hw, 0, sizeof(sdlahw_t)); + + /* for an S514 adapter, pass the CPU number and the slot number read */ + /* from 'router.conf' to the 'sdla_setup()' function via the 'port' */ + /* parameter */ + if (conf->S514_CPU_no[0]){ + + card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0]; + card->hw.S514_slot_no = conf->PCI_slot_no; + printk(KERN_INFO "Setting CPU to %c and Slot to %i\n", + card->hw.S514_cpu_no[0], card->hw.S514_slot_no); + + }else{ + /* 508 Card io port and irq initialization */ + card->hw.port = conf->ioport; + card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; + } - /* Configure hardware, load firmware, etc. */ - memset(&card->hw, 0, sizeof(sdlahw_t)); - card->hw.port = conf->ioport; - card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; - /* Compute the virtual address of the card in kernel space */ - if(conf->maddr) - card->hw.dpmbase = phys_to_virt(conf->maddr); - else /* But 0 means NULL */ - card->hw.dpmbase = (void *)conf->maddr; - - card->hw.dpmsize = SDLA_WINDOWSIZE; - card->hw.type = conf->hw_opt[0]; - card->hw.pclk = conf->hw_opt[1]; - err = sdla_setup(&card->hw, conf->data, conf->data_size); - if (err) - { - free_irq(irq, card); - return err; - } - /* Intialize WAN device data space */ - wandev->irq = irq; - wandev->dma = 0; - wandev->ioport = card->hw.port; - wandev->maddr = card->hw.dpmbase; - wandev->msize = card->hw.dpmsize; - wandev->hw_opt[0] = card->hw.type; - wandev->hw_opt[1] = card->hw.pclk; - wandev->hw_opt[2] = card->hw.memory; - wandev->hw_opt[3] = card->hw.fwid; + /* Compute the virtual address of the card in kernel space */ + if(conf->maddr) + card->hw.dpmbase = phys_to_virt(conf->maddr); + else /* But 0 means NULL */ + card->hw.dpmbase = (void *)conf->maddr; + + card->hw.dpmsize = SDLA_WINDOWSIZE; + /* set the adapter type if using an S514 adapter */ + card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; + card->hw.pclk = conf->hw_opt[1]; + + err = sdla_setup(&card->hw, conf->data, conf->data_size); + if (err){ + return err; + } + + if(card->hw.type != SDLA_S514) + irq = (conf->irq == 2) ? 9 : conf->irq; /* IRQ2 -> IRQ9 */ + else + irq = card->hw.irq; + + /* request an interrupt vector - note that interrupts may be shared */ + /* when using the S514 PCI adapter */ + if(request_irq(irq, sdla_isr, + (card->hw.type == SDLA_S514) ? SA_SHIRQ : 0, wandev->name, card)){ + + printk(KERN_ERR "%s: Can't reserve IRQ %d!\n", wandev->name, irq); + return -EINVAL; + } + + }else{ + printk(KERN_INFO "%s: Card Configured %i or Piggybacking %i!\n", + wandev->name,card->configured,card->wandev.piggyback); + } + + + if (!card->configured){ + + #ifdef __SMP__ + /* Initialize the Spin lock */ + printk(KERN_INFO "%s: Initializing SMP\n",wandev->name); + spin_lock_init(&card->lock); + #endif + + /* Intialize WAN device data space */ + wandev->irq = irq; + wandev->dma = 0; + if(card->hw.type != SDLA_S514){ + wandev->ioport = card->hw.port; + }else{ + wandev->S514_cpu_no[0] = card->hw.S514_cpu_no[0]; + wandev->S514_slot_no = card->hw.S514_slot_no; + } + wandev->maddr = (unsigned long)card->hw.dpmbase; + wandev->msize = card->hw.dpmsize; + wandev->hw_opt[0] = card->hw.type; + wandev->hw_opt[1] = card->hw.pclk; + wandev->hw_opt[2] = card->hw.memory; + wandev->hw_opt[3] = card->hw.fwid; + } /* Protocol-specific initialization */ - switch (card->hw.fwid) - { + switch (card->hw.fwid) { #ifdef CONFIG_WANPIPE_X25 case SFID_X25_502: case SFID_X25_508: @@ -325,22 +437,49 @@ static int setup (wan_device_t* wandev, wandev_conf_t* conf) break; #endif +#ifdef CONFIG_WANPIPE_CHDLC + case SFID_CHDLC508: + case SFID_CHDLC514: +// if (conf->ft1){ +// printk(KERN_INFO "%s: Starting FT1 Configurator\n", +// card->devname); +// err = wpft1_init(card, conf); +// }else{ + err = wpc_init(card, conf); +// } + break; +#endif + +#ifdef CONFIG_WANPIPE_BSTRM + case SFID_BSC502: + err = bsc_init(card, conf); + break; +#endif + +#ifdef CONFIG_WANPIPE_HDLC + case SFID_HDLC508: + err = hdlc_init(card, conf); + break; +#endif + default: - printk(KERN_ERR "%s: this firmware is not supported!\n", - wandev->name) - ; + printk(KERN_ERR "%s: this firmware is not supported %X %X!\n", + wandev->name,card->hw.fwid,SFID_CHDLC508); err = -EINVAL; } - if (err) - { - sdla_down(&card->hw); - free_irq(irq, card); + + + if (err){ + release_hw(card); return err; + } + + /* Reserve I/O region and schedule background task */ -/* printk(KERN_INFO "about to request\n");*/ - request_region(card->hw.port, card->hw.io_range, wandev->name); -/* printk(KERN_INFO "request done\n");*/ + if(card->hw.type != SDLA_S514 && !card->wandev.piggyback) + request_region(card->hw.port, card->hw.io_range, wandev->name); + if (++active == 1) queue_task(&sdla_tq, &tq_scheduler); @@ -358,7 +497,7 @@ static int setup (wan_device_t* wandev, wandev_conf_t* conf) */ static int shutdown (wan_device_t* wandev) { - sdla_t* card; + sdla_t *card; /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) @@ -367,7 +506,7 @@ static int shutdown (wan_device_t* wandev) if (wandev->state == WAN_UNCONFIGURED) return 0; - /* If wee are in a critical section we lose */ + /* If we are in a critical section we lose */ if (test_and_set_bit(0, (void*)&wandev->critical)) return -EAGAIN; @@ -376,22 +515,67 @@ static int shutdown (wan_device_t* wandev) if (--active == 0) schedule(); /* stop background thread */ - -/* printk(KERN_INFO "active now %d\n", active); - - printk(KERN_INFO "About to call sdla_down\n");*/ - sdla_down(&card->hw); -/* printk(KERN_INFO "sdla_down done\n"); - printk(KERN_INFO "About to call free_irq\n");*/ - free_irq(wandev->irq, card); -/* printk(KERN_INFO "free_irq done\n"); - printk(KERN_INFO "About to call release_region\n");*/ - release_region(card->hw.port, card->hw.io_range); -/* printk(KERN_INFO "release_region done\n");*/ + + /* Release Resources */ + release_hw(card); + + /* only free the allocated I/O range if not an S514 adapter */ + if (wandev->hw_opt[0] != SDLA_S514 && !card->configured){ + release_region(card->hw.port, card->hw.io_range); + } + + if (!card->configured){ + memset(&card->hw, 0, sizeof(sdlahw_t)); + if (card->next){ + memset(&card->next->hw, 0, sizeof(sdlahw_t)); + } + } + wandev->critical = 0; return 0; } +static void release_hw (sdla_t *card) +{ + sdla_t *nxt_card; + + /* Check if next device exists */ + if (card->next){ + nxt_card = card->next; + /* If next device is down then release resources */ + if (nxt_card->wandev.state == WAN_UNCONFIGURED){ + if (card->wandev.piggyback){ + /* If this device is piggyback then use + * information of the master device + */ + printk(KERN_INFO "%s: Piggyback shutting down\n",card->devname); + sdla_down(&card->next->hw); + free_irq(card->wandev.irq, card->next); + card->configured = 0; + card->next->configured = 0; + card->wandev.piggyback = 0; + }else{ + /* Master device shutting down */ + printk(KERN_INFO "%s: Master shutting down\n",card->devname); + sdla_down(&card->hw); + free_irq(card->wandev.irq, card); + card->configured = 0; + card->next->configured = 0; + } + }else{ + printk(KERN_INFO "%s: Device still running\n", + nxt_card->devname); + card->configured = 1; + } + }else{ + printk(KERN_INFO "%s: Master shutting down\n",card->devname); + sdla_down(&card->hw); + free_irq(card->wandev.irq, card); + card->configured = 0; + } +} + + /*============================================================================ * Driver I/O control. * o verify arguments @@ -402,20 +586,29 @@ static int shutdown (wan_device_t* wandev) */ static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg) { + sdla_t* card; int err; /* sanity checks */ if ((wandev == NULL) || (wandev->private == NULL)) - return -EFAULT - ; + return -EFAULT; if (wandev->state == WAN_UNCONFIGURED) - return -ENODEV - ; - if (test_and_set_bit(0, (void*)&wandev->critical)) - return -EAGAIN - ; - switch (cmd) - { + return -ENODEV; + + card = wandev->private; + + if(card->hw.type != SDLA_S514){ + disable_irq(card->hw.irq); + } + + if (test_and_set_bit(0, (void*)&wandev->critical)) { + if(card->hw.type != SDLA_S514){ + enable_irq(card->hw.irq); + } + return -EAGAIN; + } + + switch (cmd) { case WANPIPE_DUMP: err = ioctl_dump(wandev->private, (void*)arg); break; @@ -427,11 +620,16 @@ static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg) default: err = -EINVAL; } - wandev->critical = 0; + + clear_bit(0, (void*)&wandev->critical); + if(card->hw.type != SDLA_S514){ + enable_irq(card->hw.irq); + } + return err; } -/****** Driver IOCTL Hanlers ************************************************/ +/****** Driver IOCTL Handlers ***********************************************/ /*============================================================================ * Dump adapter memory to user buffer. @@ -458,34 +656,47 @@ static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump) if ((dump.magic != WANPIPE_MAGIC) || (dump.offset + dump.length > card->hw.memory)) return -EINVAL; - + winsize = card->hw.dpmsize; save_flags(flags); cli(); /* >>> critical section start <<< */ - oldvec = card->hw.vector; - while (dump.length) - { - unsigned pos = dump.offset % winsize; /* current offset */ - unsigned long vec = dump.offset - pos; /* current vector */ - unsigned len = (dump.length > (winsize - pos)) ? - (winsize - pos) : dump.length - ; - if (sdla_mapmem(&card->hw, vec) != 0) /* relocate window */ - { - err = -EIO; - break; - } + + if(card->hw.type != SDLA_S514) { + oldvec = card->hw.vector; + while (dump.length) { + /* current offset */ + unsigned pos = dump.offset % winsize; + /* current vector */ + unsigned long vec = dump.offset - pos; + unsigned len = (dump.length > (winsize - pos)) ? + (winsize - pos) : dump.length; + /* relocate window */ + if (sdla_mapmem(&card->hw, vec) != 0) { + err = -EIO; + break; + } + /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ + sti(); /* Not ideal but tough we have to do this */ + if(copy_to_user((void *)dump.ptr, + (u8 *)card->hw.dpmbase + pos, len)) + return -EFAULT; + cli(); + dump.length -= len; + dump.offset += len; + (char*)dump.ptr += len; + } + sdla_mapmem(&card->hw, oldvec);/* restore DPM window position */ + } + + else { /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ - sti(); /* Not ideal but tough we have to do this */ - if(copy_to_user((void *)dump.ptr, - (u8 *)card->hw.dpmbase + pos, len)) - return -EFAULT; - cli(); - dump.length -= len; - dump.offset += len; - (char*)dump.ptr += len; + sti(); /* Not ideal but tough we have to do this */ + if(copy_to_user((void *)dump.ptr, + (u8 *)card->hw.dpmbase + dump.offset, dump.length)) + return -EFAULT; + cli(); } - sdla_mapmem(&card->hw, oldvec); /* restore DPM window position */ + restore_flags(flags); /* >>> critical section end <<< */ return err; } @@ -502,9 +713,10 @@ static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec) if (card->exec == NULL) return -ENODEV; - + if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) return -EFAULT; + if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) return -EINVAL; return card->exec(card, exec.cmd, exec.data); @@ -521,21 +733,110 @@ STATIC void sdla_isr (int irq, void* dev_id, struct pt_regs *regs) { #define card ((sdla_t*)dev_id) - if (!card || (card->wandev.state == WAN_UNCONFIGURED)) - return - ; - if (card->in_isr) - { - printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n", - card->devname, card->wandev.irq) - ; - return; + if(card->hw.type == SDLA_S514) { /* handle interrrupt on S514 */ + u32 int_status; + unsigned char CPU_no = card->hw.S514_cpu_no[0]; + unsigned char card_found_for_IRQ; + u8 IRQ_count = 0; + + for(;;) { + + read_S514_int_stat(&card->hw, &int_status); + + /* check if the interrupt is for this device */ + if(!((unsigned char)int_status & + (IRQ_CPU_A | IRQ_CPU_B))) + return; + + /* if the IRQ is for both CPUs on the same adapter, */ + /* then alter the interrupt status so as to handle */ + /* one CPU at a time */ + if(((unsigned char)int_status & (IRQ_CPU_A | IRQ_CPU_B)) + == (IRQ_CPU_A | IRQ_CPU_B)) { + int_status &= (CPU_no == S514_CPU_A) ? + ~IRQ_CPU_B : ~IRQ_CPU_A; + } + + card_found_for_IRQ = 0; + + /* check to see that the CPU number for this device */ + /* corresponds to the interrupt status read */ + switch (CPU_no) { + case S514_CPU_A: + if((unsigned char)int_status & + IRQ_CPU_A) + card_found_for_IRQ = 1; + break; + + case S514_CPU_B: + if((unsigned char)int_status & + IRQ_CPU_B) + card_found_for_IRQ = 1; + break; + } + + /* exit if the interrupt is for another CPU on the */ + /* same IRQ */ + if(!card_found_for_IRQ) + return; + + if (!card || + (card->wandev.state == WAN_UNCONFIGURED && !card->configured)){ + printk(KERN_INFO + "Received IRQ %d for CPU #%c\n", + irq, CPU_no); + printk(KERN_INFO + "IRQ for unconfigured adapter\n"); + S514_intack(&card->hw, int_status); + return; + } + + if (card->in_isr) { + printk(KERN_INFO + "%s: interrupt re-entrancy on IRQ %d\n", + card->devname, card->wandev.irq); + S514_intack(&card->hw, int_status); + return; + } + + S514_intack(&card->hw, int_status); + + if (card->isr) + card->isr(card); + + /* handle a maximum of two interrupts (one for each */ + /* CPU on the adapter) before returning */ + if((++ IRQ_count) == 2) + return; + } } - sdla_intack(&card->hw); - if (card->isr) - card->isr(card); + else { /* handle interrupt on S508 adapter */ + + if (!card || ((card->wandev.state == WAN_UNCONFIGURED) && !card->configured)) + return; + if (card->in_isr) { + printk(KERN_INFO + "%s: interrupt re-entrancy on IRQ %d!\n", + card->devname, card->wandev.irq); + return; + } + + /* Use spin lock only for S508 */ + +#ifdef __SMP__ + spin_lock(&card->lock); +#endif + sdla_intack(&card->hw); + if (card->isr) + card->isr(card); +#ifdef __SMP__ + spin_unlock(&card->lock); +#endif + + } + #undef card } @@ -550,13 +851,11 @@ STATIC void sdla_poll (void* data) { int i; - for (i = 0; i < ncards; ++i) - { + for (i = 0; i < ncards; ++i) { sdla_t* card = &card_array[i]; if ((card->wandev.state != WAN_UNCONFIGURED) && card->poll && - !card->wandev.critical) - { + !card->wandev.critical) { card->poll(card); } } @@ -597,26 +896,21 @@ void wanpipe_set_state (sdla_t* card, int state) save_flags(flags); cli(); - if (card->wandev.state != state) - { - switch (state) - { + if (card->wandev.state != state) { + switch (state) { case WAN_CONNECTED: printk (KERN_INFO "%s: link connected!\n", - card->devname) - ; + card->devname); break; case WAN_CONNECTING: printk (KERN_INFO "%s: link connecting...\n", - card->devname) - ; + card->devname); break; case WAN_DISCONNECTED: printk (KERN_INFO "%s: link disconnected!\n", - card->devname) - ; + card->devname); break; } card->wandev.state = state; |