Commit c2d26a96 authored by David S. Miller's avatar David S. Miller

Merge davem@nuts.davemloft.net:/disk1/BK/net-2.6

into kernel.bkbits.net:/home/davem/net-2.6
parents 63d5381e fa58cfcf
...@@ -94,6 +94,10 @@ static struct crypto_alg cipher_null = { ...@@ -94,6 +94,10 @@ static struct crypto_alg cipher_null = {
.cia_decrypt = null_decrypt } } .cia_decrypt = null_decrypt } }
}; };
MODULE_ALIAS("compress_null");
MODULE_ALIAS("digest_null");
MODULE_ALIAS("cipher_null");
static int __init init(void) static int __init init(void)
{ {
int ret = 0; int ret = 0;
......
...@@ -385,6 +385,15 @@ config ATM_FORE200E_SBA_FW ...@@ -385,6 +385,15 @@ config ATM_FORE200E_SBA_FW
not have to supply an alternative one. They just say Y to "Use not have to supply an alternative one. They just say Y to "Use
default SBA-200E firmware", above. default SBA-200E firmware", above.
config ATM_FORE200E_USE_TASKLET
bool "Defer interrupt work to a tasklet"
depends on (PCI || SBUS) && (ATM_FORE200E_PCA || ATM_FORE200E_SBA)
default n
help
This defers work to be done by the interrupt handler to a
tasklet instead of hanlding everything at interrupt time. This
may improve the responsive of the host.
config ATM_FORE200E_TX_RETRY config ATM_FORE200E_TX_RETRY
int "Maximum number of tx retries" int "Maximum number of tx retries"
depends on (PCI || SBUS) && (ATM_FORE200E_PCA || ATM_FORE200E_SBA) depends on (PCI || SBUS) && (ATM_FORE200E_PCA || ATM_FORE200E_SBA)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
$Id: fore200e.c,v 1.5 2000/04/14 10:10:34 davem Exp $ $Id: fore200e.c,v 1.5 2000/04/14 10:10:34 davem Exp $
A FORE Systems 200E-series driver for ATM on Linux. A FORE Systems 200E-series driver for ATM on Linux.
Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2000. Christophe Lizzi (lizzi@cnam.fr), October 1999-March 2003.
Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de). Based on the PCA-200E driver from Uwe Dannowski (Uwe.Dannowski@inf.tu-dresden.de).
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/atmdev.h> #include <linux/atmdev.h>
#include <linux/sonet.h> #include <linux/sonet.h>
#include <linux/atm_suni.h> #include <linux/atm_suni.h>
...@@ -44,7 +46,6 @@ ...@@ -44,7 +46,6 @@
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <linux/pci.h>
#ifdef CONFIG_ATM_FORE200E_SBA #ifdef CONFIG_ATM_FORE200E_SBA
#include <asm/idprom.h> #include <asm/idprom.h>
...@@ -54,25 +55,33 @@ ...@@ -54,25 +55,33 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
#endif #endif
#include <linux/module.h> #if defined(CONFIG_ATM_FORE200E_USE_TASKLET) /* defer interrupt work to a tasklet */
#define FORE200E_USE_TASKLET
#endif
#include "fore200e.h" #if 0 /* enable the debugging code of the buffer supply queues */
#include "suni.h" #define FORE200E_BSQ_DEBUG
#endif
#if 1 /* ensure correct handling of 52-byte AAL0 SDUs used by atmdump-like apps */ #if 1 /* ensure correct handling of 52-byte AAL0 SDUs expected by atmdump-like apps */
#define FORE200E_52BYTE_AAL0_SDU #define FORE200E_52BYTE_AAL0_SDU
#endif #endif
#define FORE200E_VERSION "0.2d" #include "fore200e.h"
#include "suni.h"
#define FORE200E_VERSION "0.3e"
#define FORE200E "fore200e: " #define FORE200E "fore200e: "
#if 0 /* override .config */
#define CONFIG_ATM_FORE200E_DEBUG 1
#endif
#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0) #if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0)
#define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \ #define DPRINTK(level, format, args...) do { if (CONFIG_ATM_FORE200E_DEBUG >= (level)) \
printk(FORE200E format, ##args); } while(0) printk(FORE200E format, ##args); } while (0)
#else #else
#define DPRINTK(level, format, args...) while(0) #define DPRINTK(level, format, args...) do {} while (0)
#endif #endif
...@@ -89,6 +98,17 @@ ...@@ -89,6 +98,17 @@
#define MSECS(ms) (((ms)*HZ/1000)+1) #define MSECS(ms) (((ms)*HZ/1000)+1)
#if 1
#define ASSERT(expr) if (!(expr)) { \
printk(FORE200E "assertion failed! %s[%d]: %s\n", \
__FUNCTION__, __LINE__, #expr); \
panic(FORE200E "%s", __FUNCTION__); \
}
#else
#define ASSERT(expr) do {} while (0)
#endif
extern const struct atmdev_ops fore200e_ops; extern const struct atmdev_ops fore200e_ops;
extern const struct fore200e_bus fore200e_bus[]; extern const struct fore200e_bus fore200e_bus[];
...@@ -221,29 +241,6 @@ fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk) ...@@ -221,29 +241,6 @@ fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
} }
#if 0 /* currently unused */
static int
fore200e_checkup(struct fore200e* fore200e)
{
u32 hb1, hb2;
hb1 = fore200e->bus->read(&fore200e->cp_queues->heartbeat);
fore200e_spin(10);
hb2 = fore200e->bus->read(&fore200e->cp_queues->heartbeat);
if (hb2 <= hb1) {
printk(FORE200E "device %s heartbeat is not counting upwards, hb1 = %x; hb2 = %x\n",
fore200e->name, hb1, hb2);
return -EIO;
}
printk(FORE200E "device %s heartbeat is ok\n", fore200e->name);
return 0;
}
#endif
static void static void
fore200e_spin(int msecs) fore200e_spin(int msecs)
{ {
...@@ -440,7 +437,6 @@ fore200e_shutdown(struct fore200e* fore200e) ...@@ -440,7 +437,6 @@ fore200e_shutdown(struct fore200e* fore200e)
} }
#ifdef CONFIG_ATM_FORE200E_PCA #ifdef CONFIG_ATM_FORE200E_PCA
static u32 fore200e_pca_read(volatile u32* addr) static u32 fore200e_pca_read(volatile u32* addr)
...@@ -505,20 +501,16 @@ static int ...@@ -505,20 +501,16 @@ static int
fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
int size, int nbr, int alignment) int size, int nbr, int alignment)
{ {
#if defined(__sparc_v9__)
/* returned chunks are page-aligned */ /* returned chunks are page-aligned */
chunk->alloc_size = size * nbr;
chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev, chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev,
chunk->alloc_size, chunk->alloc_size,
&chunk->dma_addr); &chunk->dma_addr);
if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
return -ENOMEM; return -ENOMEM;
chunk->align_addr = chunk->alloc_addr; chunk->align_addr = chunk->alloc_addr;
#else
if (fore200e_chunk_alloc(fore200e, chunk, size * nbr, alignment, FORE200E_DMA_BIDIRECTIONAL) < 0)
return -ENOMEM;
#endif
return 0; return 0;
} }
...@@ -529,14 +521,10 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, ...@@ -529,14 +521,10 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
static void static void
fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk) fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
{ {
#if defined(__sparc_v9__)
pci_free_consistent((struct pci_dev*)fore200e->bus_dev, pci_free_consistent((struct pci_dev*)fore200e->bus_dev,
chunk->alloc_size, chunk->alloc_size,
chunk->alloc_addr, chunk->alloc_addr,
chunk->dma_addr); chunk->dma_addr);
#else
fore200e_chunk_free(fore200e, chunk);
#endif
} }
...@@ -544,7 +532,15 @@ static int ...@@ -544,7 +532,15 @@ static int
fore200e_pca_irq_check(struct fore200e* fore200e) fore200e_pca_irq_check(struct fore200e* fore200e)
{ {
/* this is a 1 bit register */ /* this is a 1 bit register */
return readl(fore200e->regs.pca.psr); int irq_posted = readl(fore200e->regs.pca.psr);
#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG == 2)
if (irq_posted && (readl(fore200e->regs.pca.hcr) & PCA200E_HCR_OUTFULL)) {
DPRINTK(2,"FIFO OUT full, device %d\n", fore200e->atm_dev->number);
}
#endif
return irq_posted;
} }
...@@ -578,7 +574,7 @@ fore200e_pca_map(struct fore200e* fore200e) ...@@ -578,7 +574,7 @@ fore200e_pca_map(struct fore200e* fore200e)
DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base); DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
/* gain access to the PCA-200E specific registers */ /* gain access to the PCA specific registers */
fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET); fore200e->regs.pca.hcr = (u32*)(fore200e->virt_base + PCA200E_HCR_OFFSET);
fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET); fore200e->regs.pca.imr = (u32*)(fore200e->virt_base + PCA200E_IMR_OFFSET);
fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET); fore200e->regs.pca.psr = (u32*)(fore200e->virt_base + PCA200E_PSR_OFFSET);
...@@ -593,8 +589,6 @@ fore200e_pca_unmap(struct fore200e* fore200e) ...@@ -593,8 +589,6 @@ fore200e_pca_unmap(struct fore200e* fore200e)
{ {
DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name); DPRINTK(2, "device %s being unmapped from memory\n", fore200e->name);
/* XXX iounmap() does nothing on PowerPC (at least in 2.2.12 and 2.3.41),
this leads to a kernel panic if the module is loaded and unloaded several times */
if (fore200e->virt_base != NULL) if (fore200e->virt_base != NULL)
iounmap(fore200e->virt_base); iounmap(fore200e->virt_base);
} }
...@@ -604,7 +598,7 @@ static int __init ...@@ -604,7 +598,7 @@ static int __init
fore200e_pca_configure(struct fore200e* fore200e) fore200e_pca_configure(struct fore200e* fore200e)
{ {
struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev; struct pci_dev* pci_dev = (struct pci_dev*)fore200e->bus_dev;
u8 master_ctrl; u8 master_ctrl, latency;
DPRINTK(2, "device %s being configured\n", fore200e->name); DPRINTK(2, "device %s being configured\n", fore200e->name);
...@@ -616,18 +610,26 @@ fore200e_pca_configure(struct fore200e* fore200e) ...@@ -616,18 +610,26 @@ fore200e_pca_configure(struct fore200e* fore200e)
pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl); pci_read_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, &master_ctrl);
master_ctrl = master_ctrl master_ctrl = master_ctrl
#if 0
| PCA200E_CTRL_DIS_CACHE_RD
| PCA200E_CTRL_DIS_WRT_INVAL
#endif
#if defined(__BIG_ENDIAN) #if defined(__BIG_ENDIAN)
/* request the PCA board to convert the endianess of slave RAM accesses */ /* request the PCA board to convert the endianess of slave RAM accesses */
| PCA200E_CTRL_CONVERT_ENDIAN | PCA200E_CTRL_CONVERT_ENDIAN
#endif
#if 0
| PCA200E_CTRL_DIS_CACHE_RD
| PCA200E_CTRL_DIS_WRT_INVAL
| PCA200E_CTRL_ENA_CONT_REQ_MODE
| PCA200E_CTRL_2_CACHE_WRT_INVAL
#endif #endif
| PCA200E_CTRL_LARGE_PCI_BURSTS; | PCA200E_CTRL_LARGE_PCI_BURSTS;
pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl); pci_write_config_byte(pci_dev, PCA200E_PCI_MASTER_CTRL, master_ctrl);
/* raise latency from 32 (default) to 192, as this seems to prevent NIC
lockups (under heavy rx loads) due to continuous 'FIFO OUT full' condition.
this may impact the performances of other PCI devices on the same bus, though */
latency = 192;
pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
fore200e->state = FORE200E_STATE_CONFIGURE; fore200e->state = FORE200E_STATE_CONFIGURE;
return 0; return 0;
} }
...@@ -656,11 +658,7 @@ fore200e_pca_detect(const struct fore200e_bus* bus, int index) ...@@ -656,11 +658,7 @@ fore200e_pca_detect(const struct fore200e_bus* bus, int index)
fore200e->bus = bus; fore200e->bus = bus;
fore200e->bus_dev = pci_dev; fore200e->bus_dev = pci_dev;
fore200e->irq = pci_dev->irq; fore200e->irq = pci_dev->irq;
fore200e->phys_base = pci_resource_start (pci_dev, 0); fore200e->phys_base = pci_resource_start(pci_dev, 0);
#if defined(__powerpc__)
fore200e->phys_base += KERNELBASE;
#endif
sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1); sprintf(fore200e->name, "%s-%d", bus->model_name, index - 1);
...@@ -728,8 +726,6 @@ fore200e_pca_proc_read(struct fore200e* fore200e, char *page) ...@@ -728,8 +726,6 @@ fore200e_pca_proc_read(struct fore200e* fore200e, char *page)
#endif /* CONFIG_ATM_FORE200E_PCA */ #endif /* CONFIG_ATM_FORE200E_PCA */
#ifdef CONFIG_ATM_FORE200E_SBA #ifdef CONFIG_ATM_FORE200E_SBA
static u32 static u32
...@@ -799,7 +795,7 @@ fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, ...@@ -799,7 +795,7 @@ fore200e_sba_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
chunk->alloc_size, chunk->alloc_size,
&chunk->dma_addr); &chunk->dma_addr);
if (chunk->alloc_addr == NULL || chunk->dma_addr == 0) if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
return -ENOMEM; return -ENOMEM;
chunk->align_addr = chunk->alloc_addr; chunk->align_addr = chunk->alloc_addr;
...@@ -858,8 +854,7 @@ fore200e_sba_map(struct fore200e* fore200e) ...@@ -858,8 +854,7 @@ fore200e_sba_map(struct fore200e* fore200e)
struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev; struct sbus_dev* sbus_dev = (struct sbus_dev*)fore200e->bus_dev;
unsigned int bursts; unsigned int bursts;
/* gain access to the SBA-200E specific registers */ /* gain access to the SBA specific registers */
fore200e->regs.sba.hcr = (u32*)sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR"); fore200e->regs.sba.hcr = (u32*)sbus_ioremap(&sbus_dev->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
fore200e->regs.sba.bsr = (u32*)sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR"); fore200e->regs.sba.bsr = (u32*)sbus_ioremap(&sbus_dev->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
fore200e->regs.sba.isr = (u32*)sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR"); fore200e->regs.sba.isr = (u32*)sbus_ioremap(&sbus_dev->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
...@@ -880,17 +875,6 @@ fore200e_sba_map(struct fore200e* fore200e) ...@@ -880,17 +875,6 @@ fore200e_sba_map(struct fore200e* fore200e)
if (sbus_can_dma_64bit(sbus_dev)) if (sbus_can_dma_64bit(sbus_dev))
sbus_set_sbus64(sbus_dev, bursts); sbus_set_sbus64(sbus_dev, bursts);
#if 0
if (bursts & DMA_BURST16)
fore200e->bus->write(SBA200E_BSR_BURST16, fore200e->regs.sba.bsr);
else
if (bursts & DMA_BURST8)
fore200e->bus->write(SBA200E_BSR_BURST8, fore200e->regs.sba.bsr);
else
if (bursts & DMA_BURST4)
fore200e->bus->write(SBA200E_BSR_BURST4, fore200e->regs.sba.bsr);
#endif
fore200e->state = FORE200E_STATE_MAP; fore200e->state = FORE200E_STATE_MAP;
return 0; return 0;
} }
...@@ -935,13 +919,11 @@ fore200e_sba_detect(const struct fore200e_bus* bus, int index) ...@@ -935,13 +919,11 @@ fore200e_sba_detect(const struct fore200e_bus* bus, int index)
return NULL; return NULL;
found: found:
#if 1
if (sbus_dev->num_registers != 4) { if (sbus_dev->num_registers != 4) {
printk(FORE200E "this %s device has %d instead of 4 registers\n", printk(FORE200E "this %s device has %d instead of 4 registers\n",
bus->model_name, sbus_dev->num_registers); bus->model_name, sbus_dev->num_registers);
return NULL; return NULL;
} }
#endif
fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL); fore200e = fore200e_kmalloc(sizeof(struct fore200e), GFP_KERNEL);
if (fore200e == NULL) if (fore200e == NULL)
...@@ -994,18 +976,26 @@ fore200e_sba_proc_read(struct fore200e* fore200e, char *page) ...@@ -994,18 +976,26 @@ fore200e_sba_proc_read(struct fore200e* fore200e, char *page)
static void static void
fore200e_irq_tx(struct fore200e* fore200e) fore200e_tx_irq(struct fore200e* fore200e)
{ {
struct host_txq* txq = &fore200e->host_txq;
struct host_txq_entry* entry; struct host_txq_entry* entry;
int i; struct atm_vcc* vcc;
struct fore200e_vc_map* vc_map;
if (fore200e->host_txq.txing == 0)
return;
entry = fore200e->host_txq.host_entry; for (;;) {
for (i = 0; i < QUEUE_SIZE_TX; i++) { entry = &txq->host_entry[ txq->tail ];
if (*entry->status & STATUS_COMPLETE) { if ((*entry->status & STATUS_COMPLETE) == 0) {
break;
}
DPRINTK(3, "TX COMPLETED: entry = %p, vcc = %p, skb = %p\n", entry, entry->vcc, entry->skb); DPRINTK(3, "TX COMPLETED: entry = %p [tail = %d], vc_map = %p, skb = %p\n",
entry, txq->tail, entry->vc_map, entry->skb);
/* free copy of misaligned data */ /* free copy of misaligned data */
if (entry->data) if (entry->data)
...@@ -1015,25 +1005,114 @@ fore200e_irq_tx(struct fore200e* fore200e) ...@@ -1015,25 +1005,114 @@ fore200e_irq_tx(struct fore200e* fore200e)
fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
FORE200E_DMA_TODEVICE); FORE200E_DMA_TODEVICE);
/* notify tx completion */ vc_map = entry->vc_map;
if (entry->vcc->pop)
entry->vcc->pop(entry->vcc, entry->skb); /* vcc closed since the time the entry was submitted for tx? */
else if ((vc_map->vcc == NULL) ||
dev_kfree_skb_irq(entry->skb); (test_bit(ATM_VF_READY, &vc_map->vcc->flags) == 0)) {
DPRINTK(1, "no ready vcc found for PDU sent on device %d\n",
fore200e->atm_dev->number);
dev_kfree_skb_any(entry->skb);
}
else {
ASSERT(vc_map->vcc);
/* vcc closed then immediately re-opened? */
if (vc_map->incarn != entry->incarn) {
/* when a vcc is closed, some PDUs may be still pending in the tx queue.
if the same vcc is immediately re-opened, those pending PDUs must
not be popped after the completion of their emission, as they refer
to the prior incarnation of that vcc. otherwise, vcc->sk->sk_wmem_alloc
would be decremented by the size of the (unrelated) skb, possibly
leading to a negative sk->sk_wmem_alloc count, ultimately freezing the vcc.
we thus bind the tx entry to the current incarnation of the vcc
when the entry is submitted for tx. When the tx later completes,
if the incarnation number of the tx entry does not match the one
of the vcc, then this implies that the vcc has been closed then re-opened.
we thus just drop the skb here. */
DPRINTK(1, "vcc closed-then-re-opened; dropping PDU sent on device %d\n",
fore200e->atm_dev->number);
dev_kfree_skb_any(entry->skb);
}
else {
vcc = vc_map->vcc;
ASSERT(vcc);
/* notify tx completion */
if (vcc->pop) {
vcc->pop(vcc, entry->skb);
}
else {
dev_kfree_skb_any(entry->skb);
}
#if 1
/* race fixed by the above incarnation mechanism, but... */
if (atomic_read(&vcc->sk->sk_wmem_alloc) < 0) {
atomic_set(&vcc->sk->sk_wmem_alloc, 0);
}
#endif
/* check error condition */ /* check error condition */
if (*entry->status & STATUS_ERROR) if (*entry->status & STATUS_ERROR)
atomic_inc(&entry->vcc->stats->tx_err); atomic_inc(&vcc->stats->tx_err);
else else
atomic_inc(&entry->vcc->stats->tx); atomic_inc(&vcc->stats->tx);
}
}
*entry->status = STATUS_FREE; *entry->status = STATUS_FREE;
fore200e->host_txq.txing--; fore200e->host_txq.txing--;
FORE200E_NEXT_ENTRY(txq->tail, QUEUE_SIZE_TX);
} }
entry++; }
#ifdef FORE200E_BSQ_DEBUG
int bsq_audit(int where, struct host_bsq* bsq, int scheme, int magn)
{
struct buffer* buffer;
int count = 0;
buffer = bsq->freebuf;
while (buffer) {
if (buffer->supplied) {
printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld supplied but in free list!\n",
where, scheme, magn, buffer->index);
}
if (buffer->magn != magn) {
printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected magn = %d\n",
where, scheme, magn, buffer->index, buffer->magn);
}
if (buffer->scheme != scheme) {
printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected scheme = %d\n",
where, scheme, magn, buffer->index, buffer->scheme);
}
if ((buffer->index < 0) || (buffer->index >= fore200e_rx_buf_nbr[ scheme ][ magn ])) {
printk(FORE200E "bsq_audit(%d): queue %d.%d, out of range buffer index = %ld !\n",
where, scheme, magn, buffer->index);
} }
count++;
buffer = buffer->next;
}
if (count != bsq->freebuf_count) {
printk(FORE200E "bsq_audit(%d): queue %d.%d, %d bufs in free list, but freebuf_count = %d\n",
where, scheme, magn, count, bsq->freebuf_count);
}
return 0;
} }
#endif
static void static void
...@@ -1050,27 +1129,41 @@ fore200e_supply(struct fore200e* fore200e) ...@@ -1050,27 +1129,41 @@ fore200e_supply(struct fore200e* fore200e)
bsq = &fore200e->host_bsq[ scheme ][ magn ]; bsq = &fore200e->host_bsq[ scheme ][ magn ];
if (fore200e_rx_buf_nbr[ scheme ][ magn ] - bsq->count > RBD_BLK_SIZE) { #ifdef FORE200E_BSQ_DEBUG
bsq_audit(1, bsq, scheme, magn);
#endif
while (bsq->freebuf_count >= RBD_BLK_SIZE) {
DPRINTK(2, "supplying rx buffers to queue %d / %d, count = %d\n", DPRINTK(2, "supplying %d rx buffers to queue %d / %d, freebuf_count = %d\n",
scheme, magn, bsq->count); RBD_BLK_SIZE, scheme, magn, bsq->freebuf_count);
entry = &bsq->host_entry[ bsq->head ]; entry = &bsq->host_entry[ bsq->head ];
FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS);
for (i = 0; i < RBD_BLK_SIZE; i++) { for (i = 0; i < RBD_BLK_SIZE; i++) {
buffer = &bsq->buffer[ bsq->free ]; /* take the first buffer in the free buffer list */
buffer = bsq->freebuf;
FORE200E_NEXT_ENTRY(bsq->free, fore200e_rx_buf_nbr[ scheme ][ magn ]); if (!buffer) {
printk(FORE200E "no more free bufs in queue %d.%d, but freebuf_count = %d\n",
scheme, magn, bsq->freebuf_count);
return;
}
bsq->freebuf = buffer->next;
#ifdef FORE200E_BSQ_DEBUG
if (buffer->supplied)
printk(FORE200E "queue %d.%d, buffer %lu already supplied\n",
scheme, magn, buffer->index);
buffer->supplied = 1;
#endif
entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr; entry->rbd_block->rbd[ i ].buffer_haddr = buffer->data.dma_addr;
entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer); entry->rbd_block->rbd[ i ].handle = FORE200E_BUF2HDL(buffer);
} }
/* increase the number of supplied rx buffers */ FORE200E_NEXT_ENTRY(bsq->head, QUEUE_SIZE_BS);
bsq->count += RBD_BLK_SIZE;
/* decrease accordingly the number of free rx buffers */
bsq->freebuf_count -= RBD_BLK_SIZE;
*entry->status = STATUS_PENDING; *entry->status = STATUS_PENDING;
fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr); fore200e->bus->write(entry->rbd_block_dma, &entry->cp_entry->rbd_block_haddr);
...@@ -1080,35 +1173,9 @@ fore200e_supply(struct fore200e* fore200e) ...@@ -1080,35 +1173,9 @@ fore200e_supply(struct fore200e* fore200e)
} }
static int
static struct atm_vcc* fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rpd)
fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
{
struct sock *s;
struct atm_vcc* vcc;
struct hlist_node *node;
read_lock(&vcc_sklist_lock);
sk_for_each(s, node, &vcc_hash[rpd->atm_header.vci & (VCC_HTABLE_SIZE-1)]) {
vcc = atm_sk(s);
if (vcc->dev != fore200e->atm_dev)
continue;
if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci) {
read_unlock(&vcc_sklist_lock);
return vcc;
}
}
read_unlock(&vcc_sklist_lock);
return NULL;
}
static void
fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
{ {
struct atm_vcc* vcc;
struct sk_buff* skb; struct sk_buff* skb;
struct buffer* buffer; struct buffer* buffer;
struct fore200e_vcc* fore200e_vcc; struct fore200e_vcc* fore200e_vcc;
...@@ -1117,15 +1184,10 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd) ...@@ -1117,15 +1184,10 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
u32 cell_header = 0; u32 cell_header = 0;
#endif #endif
vcc = fore200e_find_vcc(fore200e, rpd); ASSERT(vcc);
if (vcc == NULL) {
printk(FORE200E "no vcc found for PDU received on %d.%d.%d\n",
fore200e->atm_dev->number, rpd->atm_header.vpi, rpd->atm_header.vci);
return;
}
fore200e_vcc = FORE200E_VCC(vcc); fore200e_vcc = FORE200E_VCC(vcc);
ASSERT(fore200e_vcc);
#ifdef FORE200E_52BYTE_AAL0_SDU #ifdef FORE200E_52BYTE_AAL0_SDU
if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) { if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.rxtp.max_sdu == ATM_AAL0_SDU)) {
...@@ -1145,10 +1207,10 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd) ...@@ -1145,10 +1207,10 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
skb = alloc_skb(pdu_len, GFP_ATOMIC); skb = alloc_skb(pdu_len, GFP_ATOMIC);
if (skb == NULL) { if (skb == NULL) {
DPRINTK(2, "unable to alloc new skb, rx PDU length = %d\n", pdu_len);
printk(FORE200E "unable to alloc new skb, rx PDU length = %d\n", pdu_len);
atomic_inc(&vcc->stats->rx_drop); atomic_inc(&vcc->stats->rx_drop);
return; return -ENOMEM;
} }
do_gettimeofday(&skb->stamp); do_gettimeofday(&skb->stamp);
...@@ -1180,6 +1242,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd) ...@@ -1180,6 +1242,7 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
fore200e_vcc->rx_min_pdu = pdu_len; fore200e_vcc->rx_min_pdu = pdu_len;
if (pdu_len > fore200e_vcc->rx_max_pdu) if (pdu_len > fore200e_vcc->rx_max_pdu)
fore200e_vcc->rx_max_pdu = pdu_len; fore200e_vcc->rx_max_pdu = pdu_len;
fore200e_vcc->rx_pdu++;
/* push PDU */ /* push PDU */
if (atm_charge(vcc, skb->truesize) == 0) { if (atm_charge(vcc, skb->truesize) == 0) {
...@@ -1187,18 +1250,27 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd) ...@@ -1187,18 +1250,27 @@ fore200e_push_rpd(struct fore200e* fore200e, struct rpd* rpd)
DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n", DPRINTK(2, "receive buffers saturated for %d.%d.%d - PDU dropped\n",
vcc->itf, vcc->vpi, vcc->vci); vcc->itf, vcc->vpi, vcc->vci);
dev_kfree_skb_irq(skb); dev_kfree_skb_any(skb);
return;
atomic_inc(&vcc->stats->rx_drop);
return -ENOMEM;
} }
ASSERT(atomic_read(&vcc->sk->sk_wmem_alloc) >= 0);
vcc->push(vcc, skb); vcc->push(vcc, skb);
atomic_inc(&vcc->stats->rx); atomic_inc(&vcc->stats->rx);
ASSERT(atomic_read(&vcc->sk->sk_wmem_alloc) >= 0);
return 0;
} }
static void static void
fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd) fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd)
{ {
struct host_bsq* bsq;
struct buffer* buffer; struct buffer* buffer;
int i; int i;
...@@ -1207,17 +1279,34 @@ fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd) ...@@ -1207,17 +1279,34 @@ fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd)
/* rebuild rx buffer address from rsd handle */ /* rebuild rx buffer address from rsd handle */
buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle);
/* decrease the number of supplied rx buffers */ bsq = &fore200e->host_bsq[ buffer->scheme ][ buffer->magn ];
fore200e->host_bsq[ buffer->scheme ][ buffer->magn ].count--;
#ifdef FORE200E_BSQ_DEBUG
bsq_audit(2, bsq, buffer->scheme, buffer->magn);
if (buffer->supplied == 0)
printk(FORE200E "queue %d.%d, buffer %ld was not supplied\n",
buffer->scheme, buffer->magn, buffer->index);
buffer->supplied = 0;
#endif
/* re-insert the buffer into the free buffer list */
buffer->next = bsq->freebuf;
bsq->freebuf = buffer;
/* then increment the number of free rx buffers */
bsq->freebuf_count++;
} }
} }
static void static void
fore200e_irq_rx(struct fore200e* fore200e) fore200e_rx_irq(struct fore200e* fore200e)
{ {
struct host_rxq* rxq = &fore200e->host_rxq; struct host_rxq* rxq = &fore200e->host_rxq;
struct host_rxq_entry* entry; struct host_rxq_entry* entry;
struct atm_vcc* vcc;
struct fore200e_vc_map* vc_map;
for (;;) { for (;;) {
...@@ -1227,28 +1316,61 @@ fore200e_irq_rx(struct fore200e* fore200e) ...@@ -1227,28 +1316,61 @@ fore200e_irq_rx(struct fore200e* fore200e)
if ((*entry->status & STATUS_COMPLETE) == 0) if ((*entry->status & STATUS_COMPLETE) == 0)
break; break;
FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX); vc_map = FORE200E_VC_MAP(fore200e, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
if ((vc_map->vcc == NULL) ||
(test_bit(ATM_VF_READY, &vc_map->vcc->flags) == 0)) {
DPRINTK(1, "no ready VC found for PDU received on %d.%d.%d\n",
fore200e->atm_dev->number,
entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
}
else {
vcc = vc_map->vcc;
ASSERT(vcc);
if ((*entry->status & STATUS_ERROR) == 0) { if ((*entry->status & STATUS_ERROR) == 0) {
fore200e_push_rpd(fore200e, entry->rpd); fore200e_push_rpd(fore200e, vcc, entry->rpd);
} }
else { else {
printk(FORE200E "damaged PDU on %d.%d.%d\n", DPRINTK(2, "damaged PDU on %d.%d.%d\n",
fore200e->atm_dev->number, entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci); fore200e->atm_dev->number,
entry->rpd->atm_header.vpi, entry->rpd->atm_header.vci);
atomic_inc(&vcc->stats->rx_err);
}
} }
fore200e_collect_rpd(fore200e, entry->rpd); FORE200E_NEXT_ENTRY(rxq->head, QUEUE_SIZE_RX);
fore200e_supply(fore200e); fore200e_collect_rpd(fore200e, entry->rpd);
/* rewrite the rpd address to ack the received PDU */ /* rewrite the rpd address to ack the received PDU */
fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr); fore200e->bus->write(entry->rpd_dma, &entry->cp_entry->rpd_haddr);
*entry->status = STATUS_FREE; *entry->status = STATUS_FREE;
fore200e_supply(fore200e);
} }
} }
#ifndef FORE200E_USE_TASKLET
static void
fore200e_irq(struct fore200e* fore200e)
{
unsigned long flags;
spin_lock_irqsave(&fore200e->q_lock, flags);
fore200e_rx_irq(fore200e);
spin_unlock_irqrestore(&fore200e->q_lock, flags);
spin_lock_irqsave(&fore200e->q_lock, flags);
fore200e_tx_irq(fore200e);
spin_unlock_irqrestore(&fore200e->q_lock, flags);
}
#endif
static irqreturn_t static irqreturn_t
fore200e_interrupt(int irq, void* dev, struct pt_regs* regs) fore200e_interrupt(int irq, void* dev, struct pt_regs* regs)
{ {
...@@ -1256,58 +1378,66 @@ fore200e_interrupt(int irq, void* dev, struct pt_regs* regs) ...@@ -1256,58 +1378,66 @@ fore200e_interrupt(int irq, void* dev, struct pt_regs* regs)
if (fore200e->bus->irq_check(fore200e) == 0) { if (fore200e->bus->irq_check(fore200e) == 0) {
DPRINTK(3, "unexpected interrupt on device %c\n", fore200e->name[9]); DPRINTK(3, "interrupt NOT triggered by device %d\n", fore200e->atm_dev->number);
return IRQ_NONE; return IRQ_NONE;
} }
DPRINTK(3, "valid interrupt on device %c\n", fore200e->name[9]); DPRINTK(3, "interrupt triggered by device %d\n", fore200e->atm_dev->number);
tasklet_schedule(&fore200e->tasklet); #ifdef FORE200E_USE_TASKLET
tasklet_schedule(&fore200e->tx_tasklet);
tasklet_schedule(&fore200e->rx_tasklet);
#else
fore200e_irq(fore200e);
#endif
fore200e->bus->irq_ack(fore200e); fore200e->bus->irq_ack(fore200e);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#ifdef FORE200E_USE_TASKLET
static void static void
fore200e_tasklet(unsigned long data) fore200e_tx_tasklet(unsigned long data)
{ {
struct fore200e* fore200e = (struct fore200e*) data; struct fore200e* fore200e = (struct fore200e*) data;
unsigned long flags;
fore200e_irq_rx(fore200e); DPRINTK(3, "tx tasklet scheduled for device %d\n", fore200e->atm_dev->number);
if (fore200e->host_txq.txing) spin_lock_irqsave(&fore200e->q_lock, flags);
fore200e_irq_tx(fore200e); fore200e_tx_irq(fore200e);
spin_unlock_irqrestore(&fore200e->q_lock, flags);
} }
static void
fore200e_rx_tasklet(unsigned long data)
{
struct fore200e* fore200e = (struct fore200e*) data;
unsigned long flags;
DPRINTK(3, "rx tasklet scheduled for device %d\n", fore200e->atm_dev->number);
spin_lock_irqsave(&fore200e->q_lock, flags);
fore200e_rx_irq((struct fore200e*) data);
spin_unlock_irqrestore(&fore200e->q_lock, flags);
}
#endif
static int static int
fore200e_select_scheme(struct atm_vcc* vcc) fore200e_select_scheme(struct atm_vcc* vcc)
{ {
int scheme; /* fairly balance the VCs over (identical) buffer schemes */
int scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO;
#if 1 DPRINTK(1, "VC %d.%d.%d uses buffer scheme %d\n",
/* fairly balance VCs over (identical) buffer schemes */ vcc->itf, vcc->vpi, vcc->vci, scheme);
scheme = vcc->vci % 2 ? BUFFER_SCHEME_ONE : BUFFER_SCHEME_TWO;
#else
/* bit 7 of VPI magically selects the second buffer scheme */
if (vcc->vpi & (1<<7)) {
vcc->vpi &= ((1<<7) - 1); /* reset the magic bit */
scheme = BUFFER_SCHEME_TWO;
}
else {
scheme = BUFFER_SCHEME_ONE;
}
#endif
DPRINTK(1, "vpvc %d.%d.%d uses the %s buffer scheme\n",
vcc->itf, vcc->vpi, vcc->vci, scheme == BUFFER_SCHEME_ONE ? "first" : "second");
return scheme; return scheme;
} }
static int static int
fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu) fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu)
{ {
...@@ -1344,7 +1474,7 @@ fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* ...@@ -1344,7 +1474,7 @@ fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc*
#ifdef FORE200E_52BYTE_AAL0_SDU #ifdef FORE200E_52BYTE_AAL0_SDU
mtu = 48; mtu = 48;
#endif #endif
/* the MTU is unused by the cp, except in the case of AAL0 */ /* the MTU is not used by the cp, except in the case of AAL0 */
fore200e->bus->write(mtu, &entry->cp_entry->cmd.activate_block.mtu); fore200e->bus->write(mtu, &entry->cp_entry->cmd.activate_block.mtu);
fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.activate_block.vpvc); fore200e->bus->write(*(u32*)&vpvc, (u32*)&entry->cp_entry->cmd.activate_block.vpvc);
fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode); fore200e->bus->write(*(u32*)&activ_opcode, (u32*)&entry->cp_entry->cmd.activate_block.opcode);
...@@ -1359,13 +1489,13 @@ fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* ...@@ -1359,13 +1489,13 @@ fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc*
*entry->status = STATUS_FREE; *entry->status = STATUS_FREE;
if (ok == 0) { if (ok == 0) {
printk(FORE200E "unable to %s vpvc %d.%d on device %s\n", printk(FORE200E "unable to %s VC %d.%d.%d\n",
activate ? "open" : "close", vcc->vpi, vcc->vci, fore200e->name); activate ? "open" : "close", vcc->itf, vcc->vpi, vcc->vci);
return -EIO; return -EIO;
} }
DPRINTK(1, "vpvc %d.%d %sed on device %s\n", vcc->vpi, vcc->vci, DPRINTK(1, "VC %d.%d.%d %sed\n", vcc->itf, vcc->vpi, vcc->vci,
activate ? "open" : "clos", fore200e->name); activate ? "open" : "clos");
return 0; return 0;
} }
...@@ -1378,7 +1508,7 @@ fore200e_rate_ctrl(struct atm_qos* qos, struct tpd_rate* rate) ...@@ -1378,7 +1508,7 @@ fore200e_rate_ctrl(struct atm_qos* qos, struct tpd_rate* rate)
{ {
if (qos->txtp.max_pcr < ATM_OC3_PCR) { if (qos->txtp.max_pcr < ATM_OC3_PCR) {
/* compute the data cells to idle cells ratio from the PCR */ /* compute the data cells to idle cells ratio from the tx PCR */
rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR; rate->data_cells = qos->txtp.max_pcr * FORE200E_MAX_BACK2BACK_CELLS / ATM_OC3_PCR;
rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells; rate->idle_cells = FORE200E_MAX_BACK2BACK_CELLS - rate->data_cells;
} }
...@@ -1394,15 +1524,36 @@ fore200e_open(struct atm_vcc *vcc) ...@@ -1394,15 +1524,36 @@ fore200e_open(struct atm_vcc *vcc)
{ {
struct fore200e* fore200e = FORE200E_DEV(vcc->dev); struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
struct fore200e_vcc* fore200e_vcc; struct fore200e_vcc* fore200e_vcc;
short vpi = vcc->vpi; struct fore200e_vc_map* vc_map;
unsigned long flags;
int vci = vcc->vci; int vci = vcc->vci;
short vpi = vcc->vpi;
/* ressource checking only? */ ASSERT((vpi >= 0) && (vpi < 1<<FORE200E_VPI_BITS));
if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) ASSERT((vci >= 0) && (vci < 1<<FORE200E_VCI_BITS));
return 0;
set_bit(ATM_VF_ADDR, &vcc->flags); spin_lock_irqsave(&fore200e->q_lock, flags);
vcc->itf = vcc->dev->number;
vc_map = FORE200E_VC_MAP(fore200e, vpi, vci);
if (vc_map->vcc) {
spin_unlock_irqrestore(&fore200e->q_lock, flags);
printk(FORE200E "VC %d.%d.%d already in use\n",
fore200e->atm_dev->number, vpi, vci);
return -EINVAL;
}
vc_map->vcc = vcc;
spin_unlock_irqrestore(&fore200e->q_lock, flags);
fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_ATOMIC);
if (fore200e_vcc == NULL) {
vc_map->vcc = NULL;
return -ENOMEM;
}
DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " DPRINTK(2, "opening %d.%d.%d:%d QoS = (tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
"rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n", "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d)\n",
...@@ -1412,44 +1563,50 @@ fore200e_open(struct atm_vcc *vcc) ...@@ -1412,44 +1563,50 @@ fore200e_open(struct atm_vcc *vcc)
fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ], fore200e_traffic_class[ vcc->qos.rxtp.traffic_class ],
vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu); vcc->qos.rxtp.min_pcr, vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_cdv, vcc->qos.rxtp.max_sdu);
/* pseudo-CBR bandwidth requested? */
if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
down(&fore200e->rate_sf); down(&fore200e->rate_sf);
if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) { if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
up(&fore200e->rate_sf); up(&fore200e->rate_sf);
fore200e_kfree(fore200e_vcc);
vc_map->vcc = NULL;
return -EAGAIN; return -EAGAIN;
} }
/* reserving the pseudo-CBR bandwidth at this point grants us
to reduce the length of the critical section protected
by 'rate_sf'. in counterpart, we have to reset the available
bandwidth if we later encounter an error */
/* reserve bandwidth */
fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr; fore200e->available_cell_rate -= vcc->qos.txtp.max_pcr;
up(&fore200e->rate_sf); up(&fore200e->rate_sf);
} }
fore200e_vcc = fore200e_kmalloc(sizeof(struct fore200e_vcc), GFP_KERNEL); vcc->itf = vcc->dev->number;
if (fore200e_vcc == NULL) {
down(&fore200e->rate_sf); set_bit(ATM_VF_PARTIAL,&vcc->flags);
fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; set_bit(ATM_VF_ADDR, &vcc->flags);
up(&fore200e->rate_sf);
return -ENOMEM;
}
vcc->dev_data = fore200e_vcc; vcc->dev_data = fore200e_vcc;
if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) { if (fore200e_activate_vcin(fore200e, 1, vcc, vcc->qos.rxtp.max_sdu) < 0) {
kfree(fore200e_vcc);
down(&fore200e->rate_sf); vc_map->vcc = NULL;
clear_bit(ATM_VF_ADDR, &vcc->flags);
clear_bit(ATM_VF_PARTIAL,&vcc->flags);
vcc->dev_data = NULL;
fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
up(&fore200e->rate_sf);
return -EBUSY; fore200e_kfree(fore200e_vcc);
return -EINVAL;
} }
/* compute rate control parameters */ /* compute rate control parameters */
if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate); fore200e_rate_ctrl(&vcc->qos, &fore200e_vcc->rate);
set_bit(ATM_VF_HASQOS, &vcc->flags);
DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n", DPRINTK(3, "tx on %d.%d.%d:%d, tx PCR = %d, rx PCR = %d, data_cells = %u, idle_cells = %u\n",
vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
...@@ -1457,39 +1614,68 @@ fore200e_open(struct atm_vcc *vcc) ...@@ -1457,39 +1614,68 @@ fore200e_open(struct atm_vcc *vcc)
fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells); fore200e_vcc->rate.data_cells, fore200e_vcc->rate.idle_cells);
} }
fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = 65536; fore200e_vcc->tx_min_pdu = fore200e_vcc->rx_min_pdu = MAX_PDU_SIZE + 1;
fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0; fore200e_vcc->tx_max_pdu = fore200e_vcc->rx_max_pdu = 0;
fore200e_vcc->tx_pdu = fore200e_vcc->rx_pdu = 0;
/* new incarnation of the vcc */
vc_map->incarn = ++fore200e->incarn_count;
/* VC unusable before this flag is set */
set_bit(ATM_VF_READY, &vcc->flags); set_bit(ATM_VF_READY, &vcc->flags);
return 0; return 0;
} }
static void static void
fore200e_close(struct atm_vcc* vcc) fore200e_close(struct atm_vcc* vcc)
{ {
struct fore200e* fore200e = FORE200E_DEV(vcc->dev); struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
struct fore200e_vcc* fore200e_vcc;
struct fore200e_vc_map* vc_map;
unsigned long flags;
ASSERT(vcc);
ASSERT((vcc->vpi >= 0) && (vcc->vpi < 1<<FORE200E_VPI_BITS));
ASSERT((vcc->vci >= 0) && (vcc->vci < 1<<FORE200E_VCI_BITS));
DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal)); DPRINTK(2, "closing %d.%d.%d:%d\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal));
clear_bit(ATM_VF_READY, &vcc->flags);
fore200e_activate_vcin(fore200e, 0, vcc, 0); fore200e_activate_vcin(fore200e, 0, vcc, 0);
kfree(FORE200E_VCC(vcc)); spin_lock_irqsave(&fore200e->q_lock, flags);
vc_map = FORE200E_VC_MAP(fore200e, vcc->vpi, vcc->vci);
/* the vc is no longer considered as "in use" by fore200e_open() */
vc_map->vcc = NULL;
vcc->itf = vcc->vci = vcc->vpi = 0;
fore200e_vcc = FORE200E_VCC(vcc);
FORE200E_VCC(vcc) = NULL;
spin_unlock_irqrestore(&fore200e->q_lock, flags);
/* release reserved bandwidth, if any */
if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) { if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
down(&fore200e->rate_sf); down(&fore200e->rate_sf);
fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
up(&fore200e->rate_sf); up(&fore200e->rate_sf);
}
clear_bit(ATM_VF_READY, &vcc->flags); clear_bit(ATM_VF_HASQOS, &vcc->flags);
} }
clear_bit(ATM_VF_ADDR, &vcc->flags);
clear_bit(ATM_VF_PARTIAL,&vcc->flags);
#if 0 ASSERT(fore200e_vcc);
#define FORE200E_SYNC_SEND /* wait tx completion before returning */ fore200e_kfree(fore200e_vcc);
#endif }
static int static int
...@@ -1497,17 +1683,30 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -1497,17 +1683,30 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
{ {
struct fore200e* fore200e = FORE200E_DEV(vcc->dev); struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc);
struct fore200e_vc_map* vc_map;
struct host_txq* txq = &fore200e->host_txq; struct host_txq* txq = &fore200e->host_txq;
struct host_txq_entry* entry; struct host_txq_entry* entry;
struct tpd* tpd; struct tpd* tpd;
struct tpd_haddr tpd_haddr; struct tpd_haddr tpd_haddr;
//unsigned long flags;
int retry = CONFIG_ATM_FORE200E_TX_RETRY; int retry = CONFIG_ATM_FORE200E_TX_RETRY;
int tx_copy = 0; int tx_copy = 0;
int tx_len = skb->len; int tx_len = skb->len;
u32* cell_header = NULL; u32* cell_header = NULL;
unsigned char* skb_data; unsigned char* skb_data;
int skb_len; int skb_len;
unsigned char* data;
unsigned long flags;
ASSERT(vcc);
ASSERT(atomic_read(&vcc->sk->sk_wmem_alloc) >= 0);
ASSERT(fore200e);
ASSERT(fore200e_vcc);
if (!test_bit(ATM_VF_READY, &vcc->flags)) {
DPRINTK(1, "VC %d.%d.%d not ready for tx\n", vcc->itf, vcc->vpi, vcc->vpi);
dev_kfree_skb_any(skb);
return -EINVAL;
}
#ifdef FORE200E_52BYTE_AAL0_SDU #ifdef FORE200E_52BYTE_AAL0_SDU
if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) { if ((vcc->qos.aal == ATM_AAL0) && (vcc->qos.txtp.max_sdu == ATM_AAL0_SDU)) {
...@@ -1515,7 +1714,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -1515,7 +1714,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
skb_data = skb->data + 4; /* skip 4-byte cell header */ skb_data = skb->data + 4; /* skip 4-byte cell header */
skb_len = tx_len = skb->len - 4; skb_len = tx_len = skb->len - 4;
DPRINTK(3, "skipping user-supplied cell header 0x%08x", *cell_header); DPRINTK(3, "user-supplied cell header = 0x%08x\n", *cell_header);
} }
else else
#endif #endif
...@@ -1524,85 +1723,96 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -1524,85 +1723,96 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
skb_len = skb->len; skb_len = skb->len;
} }
if (((unsigned long)skb_data) & 0x3) {
DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name);
tx_copy = 1;
tx_len = skb_len;
}
if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) {
/* this simply NUKES the PCA board */
DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name);
tx_copy = 1;
tx_len = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD;
}
if (tx_copy) {
data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA);
if (data == NULL) {
if (vcc->pop) {
vcc->pop(vcc, skb);
}
else {
dev_kfree_skb_any(skb);
}
return -ENOMEM;
}
memcpy(data, skb_data, skb_len);
if (skb_len < tx_len)
memset(data + skb_len, 0x00, tx_len - skb_len);
}
else {
data = skb_data;
}
vc_map = FORE200E_VC_MAP(fore200e, vcc->vpi, vcc->vci);
ASSERT(vc_map->vcc == vcc);
retry_here: retry_here:
tasklet_disable(&fore200e->tasklet); spin_lock_irqsave(&fore200e->q_lock, flags);
entry = &txq->host_entry[ txq->head ]; entry = &txq->host_entry[ txq->head ];
if (*entry->status != STATUS_FREE) { if ((*entry->status != STATUS_FREE) || (txq->txing >= QUEUE_SIZE_TX - 2)) {
/* try to free completed tx queue entries */ /* try to free completed tx queue entries */
fore200e_irq_tx(fore200e); fore200e_tx_irq(fore200e);
if (*entry->status != STATUS_FREE) { if (*entry->status != STATUS_FREE) {
tasklet_enable(&fore200e->tasklet); spin_unlock_irqrestore(&fore200e->q_lock, flags);
/* retry once again? */ /* retry once again? */
if(--retry > 0) if (--retry > 0) {
schedule();
goto retry_here; goto retry_here;
}
atomic_inc(&vcc->stats->tx_err); atomic_inc(&vcc->stats->tx_err);
printk(FORE200E "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n", fore200e->tx_sat++;
DPRINTK(2, "tx queue of device %s is saturated, PDU dropped - heartbeat is %08x\n",
fore200e->name, fore200e->cp_queues->heartbeat); fore200e->name, fore200e->cp_queues->heartbeat);
if (vcc->pop) if (vcc->pop) {
vcc->pop(vcc, skb); vcc->pop(vcc, skb);
else
dev_kfree_skb(skb);
return -EIO;
} }
else {
dev_kfree_skb_any(skb);
} }
tpd = entry->tpd; if (tx_copy)
kfree(data);
if (((unsigned long)skb_data) & 0x3) {
DPRINTK(2, "misaligned tx PDU on device %s\n", fore200e->name);
tx_copy = 1;
tx_len = skb_len;
}
if ((vcc->qos.aal == ATM_AAL0) && (skb_len % ATM_CELL_PAYLOAD)) {
/* this simply NUKES the PCA-200E board */ return -ENOBUFS;
DPRINTK(2, "incomplete tx AAL0 PDU on device %s\n", fore200e->name);
tx_copy = 1;
tx_len = ((skb_len / ATM_CELL_PAYLOAD) + 1) * ATM_CELL_PAYLOAD;
} }
if (tx_copy) {
entry->data = kmalloc(tx_len, GFP_ATOMIC | GFP_DMA);
if (entry->data == NULL) {
tasklet_enable(&fore200e->tasklet);
if (vcc->pop)
vcc->pop(vcc, skb);
else
dev_kfree_skb(skb);
return -ENOMEM;
} }
memcpy(entry->data, skb_data, skb_len); entry->incarn = vc_map->incarn;
if (skb_len < tx_len) entry->vc_map = vc_map;
memset(entry->data + skb_len, 0x00, tx_len - skb_len); entry->skb = skb;
entry->data = tx_copy ? data : NULL;
tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, entry->data, tx_len, FORE200E_DMA_TODEVICE);
}
else {
entry->data = NULL;
tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, skb_data, tx_len, FORE200E_DMA_TODEVICE);
}
tpd = entry->tpd;
tpd->tsd[ 0 ].buffer = fore200e->bus->dma_map(fore200e, data, tx_len, FORE200E_DMA_TODEVICE);
tpd->tsd[ 0 ].length = tx_len; tpd->tsd[ 0 ].length = tx_len;
FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX); FORE200E_NEXT_ENTRY(txq->head, QUEUE_SIZE_TX);
txq->txing++; txq->txing++;
tasklet_enable(&fore200e->tasklet);
/* The dma_map call above implies a dma_sync so the device can use it, /* The dma_map call above implies a dma_sync so the device can use it,
* thus no explicit dma_sync call is necessary here. * thus no explicit dma_sync call is necessary here.
*/ */
...@@ -1615,9 +1825,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -1615,9 +1825,7 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
fore200e_vcc->tx_min_pdu = skb_len; fore200e_vcc->tx_min_pdu = skb_len;
if (skb_len > fore200e_vcc->tx_max_pdu) if (skb_len > fore200e_vcc->tx_max_pdu)
fore200e_vcc->tx_max_pdu = skb_len; fore200e_vcc->tx_max_pdu = skb_len;
fore200e_vcc->tx_pdu++;
entry->vcc = vcc;
entry->skb = skb;
/* set tx rate control information */ /* set tx rate control information */
tpd->rate.data_cells = fore200e_vcc->rate.data_cells; tpd->rate.data_cells = fore200e_vcc->rate.data_cells;
...@@ -1642,49 +1850,16 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -1642,49 +1850,16 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
tpd->spec.length = tx_len; tpd->spec.length = tx_len;
tpd->spec.nseg = 1; tpd->spec.nseg = 1;
tpd->spec.aal = fore200e_atm2fore_aal(vcc->qos.aal); tpd->spec.aal = fore200e_atm2fore_aal(vcc->qos.aal);
#ifdef FORE200E_SYNC_SEND
tpd->spec.intr = 0;
#else
tpd->spec.intr = 1; tpd->spec.intr = 1;
#endif
tpd_haddr.size = sizeof(struct tpd) / 32; /* size is expressed in 32 byte blocks */ tpd_haddr.size = sizeof(struct tpd) / (1<<TPD_HADDR_SHIFT); /* size is expressed in 32 byte blocks */
tpd_haddr.pad = 0; tpd_haddr.pad = 0;
tpd_haddr.haddr = entry->tpd_dma >> 5; /* shift the address, as we are in a bitfield */ tpd_haddr.haddr = entry->tpd_dma >> TPD_HADDR_SHIFT; /* shift the address, as we are in a bitfield */
*entry->status = STATUS_PENDING; *entry->status = STATUS_PENDING;
fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr); fore200e->bus->write(*(u32*)&tpd_haddr, (u32*)&entry->cp_entry->tpd_haddr);
spin_unlock_irqrestore(&fore200e->q_lock, flags);
#ifdef FORE200E_SYNC_SEND
{
int ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 10);
fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
FORE200E_DMA_TODEVICE);
/* free tmp copy of misaligned data */
if (entry->data)
kfree(entry->data);
/* notify tx completion */
if (vcc->pop)
vcc->pop(vcc, skb);
else
dev_kfree_skb(skb);
if (ok == 0) {
printk(FORE200E "synchronous tx on %d:%d:%d failed\n", vcc->itf, vcc->vpi, vcc->vci);
atomic_inc(&entry->vcc->stats->tx_err);
return -EIO;
}
atomic_inc(&entry->vcc->stats->tx);
DPRINTK(3, "synchronous tx on %d:%d:%d succeeded\n", vcc->itf, vcc->vpi, vcc->vci);
}
#endif
return 0; return 0;
} }
...@@ -1705,7 +1880,8 @@ fore200e_getstats(struct fore200e* fore200e) ...@@ -1705,7 +1880,8 @@ fore200e_getstats(struct fore200e* fore200e)
return -ENOMEM; return -ENOMEM;
} }
stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats, sizeof(struct stats), FORE200E_DMA_FROMDEVICE); stats_dma_addr = fore200e->bus->dma_map(fore200e, fore200e->stats,
sizeof(struct stats), FORE200E_DMA_FROMDEVICE);
FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
...@@ -1734,9 +1910,9 @@ fore200e_getstats(struct fore200e* fore200e) ...@@ -1734,9 +1910,9 @@ fore200e_getstats(struct fore200e* fore200e)
static int static int
fore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) fore200e_getsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen)
{ {
// struct fore200e* fore200e = FORE200E_DEV(vcc->dev); /* struct fore200e* fore200e = FORE200E_DEV(vcc->dev); */
DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", DPRINTK(2, "getsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n",
vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen);
...@@ -1748,7 +1924,7 @@ fore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval, ...@@ -1748,7 +1924,7 @@ fore200e_getsockopt (struct atm_vcc* vcc, int level, int optname, void* optval,
static int static int
fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen) fore200e_setsockopt(struct atm_vcc* vcc, int level, int optname, void* optval, int optlen)
{ {
// struct fore200e* fore200e = FORE200E_DEV(vcc->dev); /* struct fore200e* fore200e = FORE200E_DEV(vcc->dev); */
DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n", DPRINTK(2, "setsockopt %d.%d.%d, level = %d, optname = 0x%x, optval = 0x%p, optlen = %d\n",
vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen); vcc->itf, vcc->vpi, vcc->vci, level, optname, optval, optlen);
...@@ -1806,6 +1982,8 @@ fore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask) ...@@ -1806,6 +1982,8 @@ fore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask)
struct oc3_opcode opcode; struct oc3_opcode opcode;
int ok; int ok;
DPRINTK(2, "set OC-3 reg = 0x%02x, value = 0x%02x, mask = 0x%02x\n", reg, value, mask);
FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD); FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);
opcode.opcode = OPCODE_SET_OC3; opcode.opcode = OPCODE_SET_OC3;
...@@ -1861,7 +2039,7 @@ fore200e_setloop(struct fore200e* fore200e, int loop_mode) ...@@ -1861,7 +2039,7 @@ fore200e_setloop(struct fore200e* fore200e, int loop_mode)
} }
error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask); error = fore200e_set_oc3(fore200e, SUNI_MCT, mct_value, mct_mask);
if ( error == 0) if (error == 0)
fore200e->loop_mode = loop_mode; fore200e->loop_mode = loop_mode;
return error; return error;
...@@ -1943,6 +2121,11 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags) ...@@ -1943,6 +2121,11 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags)
struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc); struct fore200e_vcc* fore200e_vcc = FORE200E_VCC(vcc);
struct fore200e* fore200e = FORE200E_DEV(vcc->dev); struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
if (!test_bit(ATM_VF_READY, &vcc->flags)) {
DPRINTK(1, "VC %d.%d.%d not ready for QoS change\n", vcc->itf, vcc->vpi, vcc->vpi);
return -EINVAL;
}
DPRINTK(2, "change_qos %d.%d.%d, " DPRINTK(2, "change_qos %d.%d.%d, "
"(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; " "(tx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d; "
"rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n" "rx: cl=%s, pcr=%d-%d, cdv=%d, max_sdu=%d), flags = 0x%x\n"
...@@ -1964,6 +2147,7 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags) ...@@ -1964,6 +2147,7 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags)
fore200e->available_cell_rate += vcc->qos.txtp.max_pcr; fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
fore200e->available_cell_rate -= qos->txtp.max_pcr; fore200e->available_cell_rate -= qos->txtp.max_pcr;
up(&fore200e->rate_sf); up(&fore200e->rate_sf);
memcpy(&vcc->qos, qos, sizeof(struct atm_qos)); memcpy(&vcc->qos, qos, sizeof(struct atm_qos));
...@@ -1972,6 +2156,7 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags) ...@@ -1972,6 +2156,7 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags)
fore200e_rate_ctrl(qos, &fore200e_vcc->rate); fore200e_rate_ctrl(qos, &fore200e_vcc->rate);
set_bit(ATM_VF_HASQOS, &vcc->flags); set_bit(ATM_VF_HASQOS, &vcc->flags);
return 0; return 0;
} }
...@@ -1992,7 +2177,10 @@ fore200e_irq_request(struct fore200e* fore200e) ...@@ -1992,7 +2177,10 @@ fore200e_irq_request(struct fore200e* fore200e)
printk(FORE200E "IRQ %s reserved for device %s\n", printk(FORE200E "IRQ %s reserved for device %s\n",
fore200e_irq_itoa(fore200e->irq), fore200e->name); fore200e_irq_itoa(fore200e->irq), fore200e->name);
tasklet_init(&fore200e->tasklet, fore200e_tasklet, (unsigned long)fore200e); #ifdef FORE200E_USE_TASKLET
tasklet_init(&fore200e->tx_tasklet, fore200e_tx_tasklet, (unsigned long)fore200e);
tasklet_init(&fore200e->rx_tasklet, fore200e_rx_tasklet, (unsigned long)fore200e);
#endif
fore200e->state = FORE200E_STATE_IRQ; fore200e->state = FORE200E_STATE_IRQ;
return 0; return 0;
...@@ -2007,6 +2195,7 @@ fore200e_get_esi(struct fore200e* fore200e) ...@@ -2007,6 +2195,7 @@ fore200e_get_esi(struct fore200e* fore200e)
if (!prom) if (!prom)
return -ENOMEM; return -ENOMEM;
ok = fore200e->bus->prom_read(fore200e, prom); ok = fore200e->bus->prom_read(fore200e, prom);
if (ok < 0) { if (ok < 0) {
fore200e_kfree(prom); fore200e_kfree(prom);
...@@ -2054,10 +2243,16 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e) ...@@ -2054,10 +2243,16 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e)
if (buffer == NULL) if (buffer == NULL)
return -ENOMEM; return -ENOMEM;
bsq->freebuf = NULL;
for (i = 0; i < nbr; i++) { for (i = 0; i < nbr; i++) {
buffer[ i ].scheme = scheme; buffer[ i ].scheme = scheme;
buffer[ i ].magn = magn; buffer[ i ].magn = magn;
#ifdef FORE200E_BSQ_DEBUG
buffer[ i ].index = i;
buffer[ i ].supplied = 0;
#endif
/* allocate the receive buffer body */ /* allocate the receive buffer body */
if (fore200e_chunk_alloc(fore200e, if (fore200e_chunk_alloc(fore200e,
...@@ -2070,9 +2265,17 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e) ...@@ -2070,9 +2265,17 @@ fore200e_alloc_rx_buf(struct fore200e* fore200e)
return -ENOMEM; return -ENOMEM;
} }
/* insert the buffer into the free buffer list */
buffer[ i ].next = bsq->freebuf;
bsq->freebuf = &buffer[ i ];
} }
/* set next free buffer index */ /* all the buffers are free, initially */
bsq->free = 0; bsq->freebuf_count = nbr;
#ifdef FORE200E_BSQ_DEBUG
bsq_audit(3, bsq, scheme, magn);
#endif
} }
} }
...@@ -2258,10 +2461,11 @@ fore200e_init_tx_queue(struct fore200e* fore200e) ...@@ -2258,10 +2461,11 @@ fore200e_init_tx_queue(struct fore200e* fore200e)
we do not write here the DMA (physical) base address of each tpd into we do not write here the DMA (physical) base address of each tpd into
the related cp resident entry, because the cp relies on this write the related cp resident entry, because the cp relies on this write
operation to detect that a new pdu has been submitted for tx */ operation to detect that a new pdu has been submitted for tx */
} }
/* set the head entry of the queue */ /* set the head and tail entries of the queue */
txq->head = 0; txq->head = 0;
txq->tail = 0;
fore200e->state = FORE200E_STATE_INIT_TXQ; fore200e->state = FORE200E_STATE_INIT_TXQ;
return 0; return 0;
...@@ -2318,12 +2522,6 @@ fore200e_param_bs_queue(struct fore200e* fore200e, ...@@ -2318,12 +2522,6 @@ fore200e_param_bs_queue(struct fore200e* fore200e,
{ {
struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ]; struct bs_spec* bs_spec = &fore200e->cp_queues->init.bs_spec[ scheme ][ magn ];
/* dumb value; the firmware doesn't allow us to activate a VC while
selecting a buffer scheme with zero-sized rbd pools */
if (pool_size == 0)
pool_size = 64;
fore200e->bus->write(queue_length, &bs_spec->queue_length); fore200e->bus->write(queue_length, &bs_spec->queue_length);
fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size); fore200e->bus->write(fore200e_rx_buf_size[ scheme ][ magn ], &bs_spec->buffer_size);
fore200e->bus->write(pool_size, &bs_spec->pool_size); fore200e->bus->write(pool_size, &bs_spec->pool_size);
...@@ -2340,6 +2538,7 @@ fore200e_initialize(struct fore200e* fore200e) ...@@ -2340,6 +2538,7 @@ fore200e_initialize(struct fore200e* fore200e)
DPRINTK(2, "device %s being initialized\n", fore200e->name); DPRINTK(2, "device %s being initialized\n", fore200e->name);
init_MUTEX(&fore200e->rate_sf); init_MUTEX(&fore200e->rate_sf);
spin_lock_init(&fore200e->q_lock);
cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET); cpq = fore200e->cp_queues = (struct cp_queues*) (fore200e->virt_base + FORE200E_CP_QUEUES_OFFSET);
...@@ -2422,7 +2621,7 @@ fore200e_monitor_getc(struct fore200e* fore200e) ...@@ -2422,7 +2621,7 @@ fore200e_monitor_getc(struct fore200e* fore200e)
static void __init static void __init
fore200e_monitor_puts(struct fore200e* fore200e, char* str) fore200e_monitor_puts(struct fore200e* fore200e, char* str)
{ {
while(*str) { while (*str) {
/* the i960 monitor doesn't accept any new character if it has something to say */ /* the i960 monitor doesn't accept any new character if it has something to say */
while (fore200e_monitor_getc(fore200e) >= 0); while (fore200e_monitor_getc(fore200e) >= 0);
...@@ -2443,6 +2642,11 @@ fore200e_start_fw(struct fore200e* fore200e) ...@@ -2443,6 +2642,11 @@ fore200e_start_fw(struct fore200e* fore200e)
DPRINTK(2, "device %s firmware being started\n", fore200e->name); DPRINTK(2, "device %s firmware being started\n", fore200e->name);
#if defined(__sparc_v9__)
/* reported to be required by SBA cards on some sparc64 hosts */
fore200e_spin(100);
#endif
sprintf(cmd, "\rgo %x\r", le32_to_cpu(fw_header->start_offset)); sprintf(cmd, "\rgo %x\r", le32_to_cpu(fw_header->start_offset));
fore200e_monitor_puts(fore200e, cmd); fore200e_monitor_puts(fore200e, cmd);
...@@ -2473,12 +2677,10 @@ fore200e_load_fw(struct fore200e* fore200e) ...@@ -2473,12 +2677,10 @@ fore200e_load_fw(struct fore200e* fore200e)
DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n", DPRINTK(2, "device %s firmware being loaded at 0x%p (%d words)\n",
fore200e->name, load_addr, fw_size); fore200e->name, load_addr, fw_size);
#if 1
if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) { if (le32_to_cpu(fw_header->magic) != FW_HEADER_MAGIC) {
printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name); printk(FORE200E "corrupted %s firmware image\n", fore200e->bus->model_name);
return -ENODEV; return -ENODEV;
} }
#endif
for (; fw_size--; fw_data++, load_addr++) for (; fw_size--; fw_data++, load_addr++)
fore200e->bus->write(le32_to_cpu(*fw_data), load_addr); fore200e->bus->write(le32_to_cpu(*fw_data), load_addr);
...@@ -2505,8 +2707,8 @@ fore200e_register(struct fore200e* fore200e) ...@@ -2505,8 +2707,8 @@ fore200e_register(struct fore200e* fore200e)
atm_dev->dev_data = fore200e; atm_dev->dev_data = fore200e;
fore200e->atm_dev = atm_dev; fore200e->atm_dev = atm_dev;
atm_dev->ci_range.vpi_bits = 8; atm_dev->ci_range.vpi_bits = FORE200E_VPI_BITS;
atm_dev->ci_range.vci_bits = 10; atm_dev->ci_range.vci_bits = FORE200E_VCI_BITS;
fore200e->available_cell_rate = ATM_OC3_PCR; fore200e->available_cell_rate = ATM_OC3_PCR;
...@@ -2574,7 +2776,7 @@ fore200e_module_init(void) ...@@ -2574,7 +2776,7 @@ fore200e_module_init(void)
struct fore200e* fore200e; struct fore200e* fore200e;
int index, link; int index, link;
printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n"); printk(FORE200E "FORE Systems 200E-series ATM driver - version " FORE200E_VERSION "\n");
/* for each configured bus interface */ /* for each configured bus interface */
for (link = 0, bus = fore200e_bus; bus->model_name; bus++) { for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
...@@ -2622,12 +2824,13 @@ fore200e_module_cleanup(void) ...@@ -2622,12 +2824,13 @@ fore200e_module_cleanup(void)
static int static int
fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
{ {
struct sock *s;
struct hlist_node *node;
struct fore200e* fore200e = FORE200E_DEV(dev); struct fore200e* fore200e = FORE200E_DEV(dev);
struct fore200e_vcc* fore200e_vcc;
struct atm_vcc* vcc;
int i, len, left = *pos; int i, len, left = *pos;
unsigned long flags;
if (!left--) { if (!left--) {
...@@ -2660,14 +2863,15 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) ...@@ -2660,14 +2863,15 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
if (!left--) if (!left--)
return sprintf(page, return sprintf(page,
" supplied small bufs (1):\t%d\n" " free small bufs, scheme 1:\t%d\n"
" supplied large bufs (1):\t%d\n" " free large bufs, scheme 1:\t%d\n"
" supplied small bufs (2):\t%d\n" " free small bufs, scheme 2:\t%d\n"
" supplied large bufs (2):\t%d\n", " free large bufs, scheme 2:\t%d\n",
fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].count, fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_SMALL ].freebuf_count,
fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].count, fore200e->host_bsq[ BUFFER_SCHEME_ONE ][ BUFFER_MAGN_LARGE ].freebuf_count,
fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].count, fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_SMALL ].freebuf_count,
fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].count); fore200e->host_bsq[ BUFFER_SCHEME_TWO ][ BUFFER_MAGN_LARGE ].freebuf_count);
if (!left--) { if (!left--) {
u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat); u32 hb = fore200e->bus->read(&fore200e->cp_queues->heartbeat);
...@@ -2706,7 +2910,7 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) ...@@ -2706,7 +2910,7 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type)); u32 media_index = FORE200E_MEDIA_INDEX(fore200e->bus->read(&fore200e->cp_queues->media_type));
u32 oc3_index; u32 oc3_index;
if (media_index < 0 || media_index > 4) if ((media_index < 0) || (media_index > 4))
media_index = 5; media_index = 5;
switch (fore200e->loop_mode) { switch (fore200e->loop_mode) {
...@@ -2853,12 +3057,14 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) ...@@ -2853,12 +3057,14 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
" large b1:\t\t\t%10u\n" " large b1:\t\t\t%10u\n"
" small b2:\t\t\t%10u\n" " small b2:\t\t\t%10u\n"
" large b2:\t\t\t%10u\n" " large b2:\t\t\t%10u\n"
" RX PDUs:\t\t\t%10u\n", " RX PDUs:\t\t\t%10u\n"
" TX PDUs:\t\t\t%10lu\n",
fore200e_swap(fore200e->stats->aux.small_b1_failed), fore200e_swap(fore200e->stats->aux.small_b1_failed),
fore200e_swap(fore200e->stats->aux.large_b1_failed), fore200e_swap(fore200e->stats->aux.large_b1_failed),
fore200e_swap(fore200e->stats->aux.small_b2_failed), fore200e_swap(fore200e->stats->aux.small_b2_failed),
fore200e_swap(fore200e->stats->aux.large_b2_failed), fore200e_swap(fore200e->stats->aux.large_b2_failed),
fore200e_swap(fore200e->stats->aux.rpd_alloc_failed)); fore200e_swap(fore200e->stats->aux.rpd_alloc_failed),
fore200e->tx_sat);
if (!left--) if (!left--)
return sprintf(page,"\n" return sprintf(page,"\n"
...@@ -2866,40 +3072,43 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page) ...@@ -2866,40 +3072,43 @@ fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
fore200e->stats->aux.receive_carrier ? "ON" : "OFF!"); fore200e->stats->aux.receive_carrier ? "ON" : "OFF!");
if (!left--) { if (!left--) {
struct atm_vcc *vcc; return sprintf(page,"\n"
struct fore200e_vcc* fore200e_vcc; " VCCs:\n address VPI VCI AAL "
"TX PDUs TX min/max size RX PDUs RX min/max size\n");
len = sprintf(page,"\n" }
" VCCs:\n address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
read_lock(&vcc_sklist_lock); for (i = 0; i < NBR_CONNECT; i++) {
for(i = 0; i < VCC_HTABLE_SIZE; ++i) {
struct hlist_head *head = &vcc_hash[i];
sk_for_each(s, node, head) { vcc = fore200e->vc_map[i].vcc;
vcc = atm_sk(s);
if (vcc->dev != fore200e->atm_dev) if (vcc == NULL)
continue; continue;
spin_lock_irqsave(&fore200e->q_lock, flags);
if (vcc && test_bit(ATM_VF_READY, &vcc->flags) && !left--) {
fore200e_vcc = FORE200E_VCC(vcc); fore200e_vcc = FORE200E_VCC(vcc);
ASSERT(fore200e_vcc);
len += sprintf(page + len, len = sprintf(page,
" %x\t%d.%d:%d\t\t(%d/%d)\t(%d/%d)\n", " %08x %03d %05d %1d %09lu %05d/%05d %09lu %05d/%05d\n",
(u32)(unsigned long)vcc, (u32)(unsigned long)vcc,
vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal),
fore200e_vcc->tx_pdu,
fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu, fore200e_vcc->tx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->tx_min_pdu,
fore200e_vcc->tx_max_pdu, fore200e_vcc->tx_max_pdu,
fore200e_vcc->rx_pdu,
fore200e_vcc->rx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->rx_min_pdu, fore200e_vcc->rx_min_pdu > 0xFFFF ? 0 : fore200e_vcc->rx_min_pdu,
fore200e_vcc->rx_max_pdu fore200e_vcc->rx_max_pdu);
);
}
}
read_unlock(&vcc_sklist_lock);
spin_unlock_irqrestore(&fore200e->q_lock, flags);
return len; return len;
} }
spin_unlock_irqrestore(&fore200e->q_lock, flags);
}
return 0; return 0;
} }
...@@ -2917,7 +3126,7 @@ static const struct atmdev_ops fore200e_ops = ...@@ -2917,7 +3126,7 @@ static const struct atmdev_ops fore200e_ops =
.send = fore200e_send, .send = fore200e_send,
.change_qos = fore200e_change_qos, .change_qos = fore200e_change_qos,
.proc_read = fore200e_proc_read, .proc_read = fore200e_proc_read,
.owner = THIS_MODULE, .owner = THIS_MODULE
}; };
...@@ -2980,4 +3189,6 @@ static const struct fore200e_bus fore200e_bus[] = { ...@@ -2980,4 +3189,6 @@ static const struct fore200e_bus fore200e_bus[] = {
{} {}
}; };
#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#endif
...@@ -23,19 +23,21 @@ ...@@ -23,19 +23,21 @@
#define BUFFER_S2_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 2 */ #define BUFFER_S2_SIZE SMALL_BUFFER_SIZE /* size of small buffers, scheme 2 */
#define BUFFER_L2_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 2 */ #define BUFFER_L2_SIZE LARGE_BUFFER_SIZE /* size of large buffers, scheme 2 */
#define BUFFER_S1_NBR (RBD_BLK_SIZE * 2) #define BUFFER_S1_NBR (RBD_BLK_SIZE * 6)
#define BUFFER_L1_NBR (RBD_BLK_SIZE * 2) #define BUFFER_L1_NBR (RBD_BLK_SIZE * 4)
#define BUFFER_S2_NBR (RBD_BLK_SIZE * 2) #define BUFFER_S2_NBR (RBD_BLK_SIZE * 6)
#define BUFFER_L2_NBR (RBD_BLK_SIZE * 2) #define BUFFER_L2_NBR (RBD_BLK_SIZE * 4)
#define QUEUE_SIZE_CMD 16 /* command queue capacity */ #define QUEUE_SIZE_CMD 16 /* command queue capacity */
#define QUEUE_SIZE_RX 64 /* receive queue capacity */ #define QUEUE_SIZE_RX 64 /* receive queue capacity */
#define QUEUE_SIZE_TX 256 /* transmit queue capacity */ #define QUEUE_SIZE_TX 256 /* transmit queue capacity */
#define QUEUE_SIZE_BS 16 /* buffer supply queue capacity */ #define QUEUE_SIZE_BS 32 /* buffer supply queue capacity */
#define NBR_CONNECT 1024 /* number of ATM connections */ #define FORE200E_VPI_BITS 0
#define FORE200E_VCI_BITS 10
#define NBR_CONNECT (1 << (FORE200E_VPI_BITS + FORE200E_VCI_BITS)) /* number of connections */
#define TSD_FIXED 2 #define TSD_FIXED 2
...@@ -207,6 +209,7 @@ typedef struct tpd_haddr { ...@@ -207,6 +209,7 @@ typedef struct tpd_haddr {
) )
} tpd_haddr_t; } tpd_haddr_t;
#define TPD_HADDR_SHIFT 5 /* addr aligned on 32 byte boundary */
/* cp resident transmit queue entry */ /* cp resident transmit queue entry */
...@@ -522,8 +525,10 @@ typedef struct host_txq_entry { ...@@ -522,8 +525,10 @@ typedef struct host_txq_entry {
struct tpd* tpd; /* addr of transmit PDU descriptor */ struct tpd* tpd; /* addr of transmit PDU descriptor */
u32 tpd_dma; /* DMA address of tpd */ u32 tpd_dma; /* DMA address of tpd */
struct sk_buff* skb; /* related skb */ struct sk_buff* skb; /* related skb */
struct atm_vcc* vcc; /* related vcc */
void* data; /* copy of misaligned data */ void* data; /* copy of misaligned data */
unsigned long incarn; /* vc_map incarnation when submitted for tx */
struct fore200e_vc_map* vc_map;
} host_txq_entry_t; } host_txq_entry_t;
...@@ -576,6 +581,10 @@ typedef struct buffer { ...@@ -576,6 +581,10 @@ typedef struct buffer {
enum buffer_scheme scheme; /* buffer scheme */ enum buffer_scheme scheme; /* buffer scheme */
enum buffer_magn magn; /* buffer magnitude */ enum buffer_magn magn; /* buffer magnitude */
struct chunk data; /* data buffer */ struct chunk data; /* data buffer */
#ifdef FORE200E_BSQ_DEBUG
unsigned long index; /* buffer # in queue */
int supplied; /* 'buffer supplied' flag */
#endif
} buffer_t; } buffer_t;
...@@ -602,6 +611,7 @@ typedef struct host_cmdq { ...@@ -602,6 +611,7 @@ typedef struct host_cmdq {
typedef struct host_txq { typedef struct host_txq {
struct host_txq_entry host_entry[ QUEUE_SIZE_TX ]; /* host resident tx queue entries */ struct host_txq_entry host_entry[ QUEUE_SIZE_TX ]; /* host resident tx queue entries */
int head; /* head of tx queue */ int head; /* head of tx queue */
int tail; /* tail of tx queue */
struct chunk tpd; /* array of tpds */ struct chunk tpd; /* array of tpds */
struct chunk status; /* arry of completion status */ struct chunk status; /* arry of completion status */
int txing; /* number of pending PDUs in tx queue */ int txing; /* number of pending PDUs in tx queue */
...@@ -626,8 +636,8 @@ typedef struct host_bsq { ...@@ -626,8 +636,8 @@ typedef struct host_bsq {
struct chunk rbd_block; /* array of rbds */ struct chunk rbd_block; /* array of rbds */
struct chunk status; /* array of completion status */ struct chunk status; /* array of completion status */
struct buffer* buffer; /* array of rx buffers */ struct buffer* buffer; /* array of rx buffers */
int free; /* index of first free rx buffer */ struct buffer* freebuf; /* list of free rx buffers */
volatile int count; /* count of supplied rx buffers */ volatile int freebuf_count; /* count of free rx buffers */
} host_bsq_t; } host_bsq_t;
...@@ -847,6 +857,17 @@ typedef struct fore200e_bus { ...@@ -847,6 +857,17 @@ typedef struct fore200e_bus {
#endif #endif
/* vc mapping */
typedef struct fore200e_vc_map {
struct atm_vcc* vcc; /* vcc entry */
unsigned long incarn; /* vcc incarnation number */
} fore200e_vc_map_t;
#define FORE200E_VC_MAP(fore200e, vpi, vci) \
(& (fore200e)->vc_map[ ((vpi) << FORE200E_VCI_BITS) | (vci) ])
/* per-device data */ /* per-device data */
typedef struct fore200e { typedef struct fore200e {
...@@ -880,8 +901,15 @@ typedef struct fore200e { ...@@ -880,8 +901,15 @@ typedef struct fore200e {
struct stats* stats; /* last snapshot of the stats */ struct stats* stats; /* last snapshot of the stats */
struct semaphore rate_sf; /* protects rate reservation ops */ struct semaphore rate_sf; /* protects rate reservation ops */
struct tasklet_struct tasklet; /* performs interrupt work */ spinlock_t q_lock; /* protects queue ops */
#ifdef FORE200E_USE_TASKLET
struct tasklet_struct tx_tasklet; /* performs tx interrupt work */
struct tasklet_struct rx_tasklet; /* performs rx interrupt work */
#endif
unsigned long tx_sat; /* tx queue saturation count */
unsigned long incarn_count;
struct fore200e_vc_map vc_map[ NBR_CONNECT ]; /* vc mapping */
} fore200e_t; } fore200e_t;
...@@ -894,6 +922,8 @@ typedef struct fore200e_vcc { ...@@ -894,6 +922,8 @@ typedef struct fore200e_vcc {
int rx_max_pdu; /* size of largest PDU received */ int rx_max_pdu; /* size of largest PDU received */
int tx_min_pdu; /* size of smallest PDU transmitted */ int tx_min_pdu; /* size of smallest PDU transmitted */
int tx_max_pdu; /* size of largest PDU transmitted */ int tx_max_pdu; /* size of largest PDU transmitted */
unsigned long tx_pdu; /* nbr of tx pdus */
unsigned long rx_pdu; /* nbr of rx pdus */
} fore200e_vcc_t; } fore200e_vcc_t;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/types.h> /* for "__kernel_caddr_t" et al */ #include <linux/types.h> /* for "__kernel_caddr_t" et al */
#include <linux/socket.h> /* for "struct sockaddr" et al */ #include <linux/socket.h> /* for "struct sockaddr" et al */
#include <linux/compiler.h> /* for "__user" et al */
#define IFNAMSIZ 16 #define IFNAMSIZ 16
#include <linux/hdlc/ioctl.h> #include <linux/hdlc/ioctl.h>
......
...@@ -98,9 +98,10 @@ enum ...@@ -98,9 +98,10 @@ enum
TCPDIAG_NONE, TCPDIAG_NONE,
TCPDIAG_MEMINFO, TCPDIAG_MEMINFO,
TCPDIAG_INFO, TCPDIAG_INFO,
TCPDIAG_VEGASINFO,
}; };
#define TCPDIAG_MAX TCPDIAG_INFO #define TCPDIAG_MAX TCPDIAG_VEGASINFO
/* TCPDIAG_MEM */ /* TCPDIAG_MEM */
...@@ -113,4 +114,14 @@ struct tcpdiag_meminfo ...@@ -113,4 +114,14 @@ struct tcpdiag_meminfo
__u32 tcpdiag_tmem; __u32 tcpdiag_tmem;
}; };
/* TCPDIAG_VEGASINFO */
struct tcpvegas_info {
__u32 tcpv_enabled;
__u32 tcpv_rttcnt;
__u32 tcpv_rtt;
__u32 tcpv_minrtt;
};
#endif /* _TCP_DIAG_H_ */ #endif /* _TCP_DIAG_H_ */
...@@ -50,6 +50,7 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, ...@@ -50,6 +50,7 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
struct tcp_info *info = NULL; struct tcp_info *info = NULL;
struct tcpdiag_meminfo *minfo = NULL; struct tcpdiag_meminfo *minfo = NULL;
struct tcpvegas_info *vinfo = NULL;
unsigned char *b = skb->tail; unsigned char *b = skb->tail;
nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r)); nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r));
...@@ -59,6 +60,9 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, ...@@ -59,6 +60,9 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
minfo = TCPDIAG_PUT(skb, TCPDIAG_MEMINFO, sizeof(*minfo)); minfo = TCPDIAG_PUT(skb, TCPDIAG_MEMINFO, sizeof(*minfo));
if (ext & (1<<(TCPDIAG_INFO-1))) if (ext & (1<<(TCPDIAG_INFO-1)))
info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info)); info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info));
if (tcp_is_vegas(tp) && (ext & (1<<(TCPDIAG_VEGASINFO-1))))
vinfo = TCPDIAG_PUT(skb, TCPDIAG_VEGASINFO, sizeof(*vinfo));
} }
r->tcpdiag_family = sk->sk_family; r->tcpdiag_family = sk->sk_family;
r->tcpdiag_state = sk->sk_state; r->tcpdiag_state = sk->sk_state;
...@@ -196,6 +200,13 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk, ...@@ -196,6 +200,13 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
info->tcpi_reordering = tp->reordering; info->tcpi_reordering = tp->reordering;
} }
if (vinfo) {
vinfo->tcpv_enabled = tp->vegas.doing_vegas_now;
vinfo->tcpv_rttcnt = tp->vegas.cntRTT;
vinfo->tcpv_rtt = tp->vegas.baseRTT;
vinfo->tcpv_minrtt = tp->vegas.minRTT;
}
nlh->nlmsg_len = skb->tail - b; nlh->nlmsg_len = skb->tail - b;
return skb->len; return skb->len;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment