Commit 927f6aaa authored by Chas Williams's avatar Chas Williams Committed by Stephen Hemminger

[ATM]: Update LANAI driver to modern PCI and DMA APIs (from mitch@sfgoth.com)

parent d98e960e
/* lanai.c -- Copyright 1999 by Mitchell Blank Jr <mitch@sfgoth.com> /* lanai.c -- Copyright 1999-2003 by Mitchell Blank Jr <mitch@sfgoth.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
*/ */
/* Version history: /* Version history:
* v.1.00 -- 26-JUL-2003 -- PCI/DMA updates
* v.0.02 -- 11-JAN-2000 -- Endian fixes * v.0.02 -- 11-JAN-2000 -- Endian fixes
* v.0.01 -- 30-NOV-1999 -- Initial release * v.0.01 -- 30-NOV-1999 -- Initial release
*/ */
...@@ -178,7 +179,7 @@ ...@@ -178,7 +179,7 @@
printk(KERN_DEBUG DEV_LABEL ": " format, ##args) printk(KERN_DEBUG DEV_LABEL ": " format, ##args)
#define APRINTK(truth, format, args...) \ #define APRINTK(truth, format, args...) \
do { \ do { \
if (!(truth)) \ if (unlikely(!(truth))) \
printk(KERN_ERR DEV_LABEL ": " format, ##args); \ printk(KERN_ERR DEV_LABEL ": " format, ##args); \
} while (0) } while (0)
...@@ -215,7 +216,7 @@ struct lanai_buffer { ...@@ -215,7 +216,7 @@ struct lanai_buffer {
u32 *start; /* From get_free_pages */ u32 *start; /* From get_free_pages */
u32 *end; /* One past last byte */ u32 *end; /* One past last byte */
u32 *ptr; /* Pointer to current host location */ u32 *ptr; /* Pointer to current host location */
int order; /* log2(size/PAGE_SIZE) */ dma_addr_t dmaaddr;
}; };
struct lanai_vcc_stats { struct lanai_vcc_stats {
...@@ -373,89 +374,76 @@ static void vci_bitfield_iterate(struct lanai_dev *lanai, ...@@ -373,89 +374,76 @@ static void vci_bitfield_iterate(struct lanai_dev *lanai,
/* /*
* Lanai needs DMA buffers aligned to 256 bytes of at least 1024 bytes - * Lanai needs DMA buffers aligned to 256 bytes of at least 1024 bytes -
* we assume that any page allocation will do. I'm sure this is * usually any page allocation will do. Just to be safe in case
* never going to be a problem, but it's good to document assumtions * PAGE_SIZE is insanely tiny, though...
*/ */
#if PAGE_SIZE < 1024 #define LANAI_PAGE_SIZE ((PAGE_SIZE >= 1024) ? PAGE_SIZE : 1024)
#error PAGE_SIZE too small to support LANAI chipset
#endif
/*
* We also assume that the maximum buffer size will be some number
* of whole pages, although that wouldn't be too hard to fix
*/
#if PAGE_SIZE > (128 * 1024)
#error PAGE_SIZE too large to support LANAI chipset
#endif
/* Convert a size to "order" for __get_free_pages */
static int bytes_to_order(int bytes)
{
int order = 0;
if (bytes > (128 * 1024))
bytes = 128 * 1024; /* Max buffer size for lanai */
while ((PAGE_SIZE << order) < bytes)
order++;
return order;
}
/* /*
* Allocate a buffer in host RAM for service list, RX, or TX * Allocate a buffer in host RAM for service list, RX, or TX
* Returns buf->order<0 if no memory * Returns buf->start==NULL if no memory
* Note that the size will be rounded up to an "order" of pages, and * Note that the size will be rounded up 2^n bytes, and
* if we can't allocate that we'll settle for something smaller * if we can't allocate that we'll settle for something smaller
* until minbytes * until minbytes
*
* NOTE: buffer must be 32-bit DMA capable - when linux can
* make distinction, this will need tweaking for this
* to work on BIG memory machines.
*/ */
static void lanai_buf_allocate(struct lanai_buffer *buf, static void lanai_buf_allocate(struct lanai_buffer *buf,
int bytes, int minbytes) size_t bytes, size_t minbytes, struct pci_dev *pci)
{ {
unsigned long address; int size;
int order = bytes_to_order(bytes);
if (bytes > (128 * 1024)) /* max lanai buffer size */
bytes = 128 * 1024;
for (size = LANAI_PAGE_SIZE; size < bytes; size *= 2)
;
if (minbytes < LANAI_PAGE_SIZE)
minbytes = LANAI_PAGE_SIZE;
do { do {
address = __get_free_pages(GFP_KERNEL, order); /*
if (address != 0) { /* Success */ * Technically we could use non-consistent mappings for
bytes = PAGE_SIZE << order; * everything, but the way the lanai uses DMA memory would
buf->start = buf->ptr = (u32 *) address; * make that a terrific pain. This is much simpler.
buf->end = (u32 *) (address + bytes); */
memset((void *) address, 0, bytes); buf->start = pci_alloc_consistent(pci, size, &buf->dmaaddr);
if (buf->start != NULL) { /* Success */
/* Lanai requires 256-byte alignment of DMA bufs */
APRINTK((buf->dmaaddr & ~0xFFFFFF00) == 0,
"bad dmaaddr: 0x%lx\n",
(unsigned long) buf->dmaaddr);
buf->ptr = buf->start;
buf->end = (u32 *)
(&((unsigned char *) buf->start)[size]);
memset(buf->start, 0, size);
break; break;
} }
if ((PAGE_SIZE << --order) < minbytes) size /= 2;
order = -1; /* Too small - give up */ } while (size >= minbytes);
} while (order >= 0);
buf->order = order;
}
static inline void lanai_buf_deallocate(struct lanai_buffer *buf)
{
if (buf->order >= 0) {
APRINTK(buf->start != 0, "lanai_buf_deallocate: start==0!\n");
free_pages((unsigned long) buf->start, buf->order);
buf->start = buf->end = buf->ptr = 0;
}
} }
/* size of buffer in bytes */ /* size of buffer in bytes */
static inline int lanai_buf_size(const struct lanai_buffer *buf) static inline size_t lanai_buf_size(const struct lanai_buffer *buf)
{ {
return ((unsigned long) buf->end) - ((unsigned long) buf->start); return ((unsigned long) buf->end) - ((unsigned long) buf->start);
} }
/* size of buffer as "card order" (0=1k .. 7=128k) */ static void lanai_buf_deallocate(struct lanai_buffer *buf,
static inline int lanai_buf_size_cardorder(const struct lanai_buffer *buf) struct pci_dev *pci)
{ {
return buf->order + PAGE_SHIFT - 10; if (buf->start != NULL) {
pci_free_consistent(pci, lanai_buf_size(buf),
buf->start, buf->dmaaddr);
buf->start = buf->end = buf->ptr = NULL;
}
} }
/* DMA-able address for this buffer */ /* size of buffer as "card order" (0=1k .. 7=128k) */
static unsigned long lanai_buf_dmaaddr(const struct lanai_buffer *buf) static int lanai_buf_size_cardorder(const struct lanai_buffer *buf)
{ {
unsigned long r = virt_to_bus(buf->start); int order = get_order(lanai_buf_size(buf)) + (PAGE_SHIFT - 10);
APRINTK((r & ~0xFFFFFF00) == 0, "bad dmaaddr: 0x%lx\n", (long) r);
return r; /* This can only happen if PAGE_SIZE is gigantic, but just in case */
if (order > 7)
order = 7;
return order;
} }
/* -------------------- HANDLE BACKLOG_VCCS BITFIELD: */ /* -------------------- HANDLE BACKLOG_VCCS BITFIELD: */
...@@ -492,7 +480,7 @@ enum lanai_register { ...@@ -492,7 +480,7 @@ enum lanai_register {
Reset_Reg = 0x00, /* Reset; read for chip type; bits: */ Reset_Reg = 0x00, /* Reset; read for chip type; bits: */
#define RESET_GET_BOARD_REV(x) (((x)>> 0)&0x03) /* Board revision */ #define RESET_GET_BOARD_REV(x) (((x)>> 0)&0x03) /* Board revision */
#define RESET_GET_BOARD_ID(x) (((x)>> 2)&0x03) /* Board ID */ #define RESET_GET_BOARD_ID(x) (((x)>> 2)&0x03) /* Board ID */
#define BOARD_ID_LANAI256 (0) /* 25.6M adaptor card */ #define BOARD_ID_LANAI256 (0) /* 25.6M adapter card */
Endian_Reg = 0x04, /* Endian setting */ Endian_Reg = 0x04, /* Endian setting */
IntStatus_Reg = 0x08, /* Interrupt status */ IntStatus_Reg = 0x08, /* Interrupt status */
IntStatusMasked_Reg = 0x0C, /* Interrupt status (masked) */ IntStatusMasked_Reg = 0x0C, /* Interrupt status (masked) */
...@@ -850,7 +838,7 @@ static void host_vcc_start_rx(const struct lanai_vcc *lvcc) ...@@ -850,7 +838,7 @@ static void host_vcc_start_rx(const struct lanai_vcc *lvcc)
{ {
u32 addr1; u32 addr1;
if (lvcc->rx.atmvcc->qos.aal == ATM_AAL5) { if (lvcc->rx.atmvcc->qos.aal == ATM_AAL5) {
unsigned long dmaaddr = lanai_buf_dmaaddr(&lvcc->rx.buf); dma_addr_t dmaaddr = lvcc->rx.buf.dmaaddr;
cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc1); cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc1);
cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc2); cardvcc_write(lvcc, 0xFFFF, vcc_rxcrc2);
cardvcc_write(lvcc, 0, vcc_rxwriteptr); cardvcc_write(lvcc, 0, vcc_rxwriteptr);
...@@ -872,7 +860,7 @@ static void host_vcc_start_rx(const struct lanai_vcc *lvcc) ...@@ -872,7 +860,7 @@ static void host_vcc_start_rx(const struct lanai_vcc *lvcc)
static void host_vcc_start_tx(const struct lanai_vcc *lvcc) static void host_vcc_start_tx(const struct lanai_vcc *lvcc)
{ {
unsigned long dmaaddr = lanai_buf_dmaaddr(&lvcc->tx.buf); dma_addr_t dmaaddr = lvcc->tx.buf.dmaaddr;
cardvcc_write(lvcc, 0, vcc_txicg); cardvcc_write(lvcc, 0, vcc_txicg);
cardvcc_write(lvcc, 0xFFFF, vcc_txcrc1); cardvcc_write(lvcc, 0xFFFF, vcc_txcrc1);
cardvcc_write(lvcc, 0xFFFF, vcc_txcrc2); cardvcc_write(lvcc, 0xFFFF, vcc_txcrc2);
...@@ -971,14 +959,15 @@ static void lanai_shutdown_tx_vci(struct lanai_dev *lanai, ...@@ -971,14 +959,15 @@ static void lanai_shutdown_tx_vci(struct lanai_dev *lanai,
static inline int aal0_buffer_allocate(struct lanai_dev *lanai) static inline int aal0_buffer_allocate(struct lanai_dev *lanai)
{ {
DPRINTK("aal0_buffer_allocate: allocating AAL0 RX buffer\n"); DPRINTK("aal0_buffer_allocate: allocating AAL0 RX buffer\n");
lanai_buf_allocate(&lanai->aal0buf, AAL0_RX_BUFFER_SIZE, 80); lanai_buf_allocate(&lanai->aal0buf, AAL0_RX_BUFFER_SIZE, 80,
return (lanai->aal0buf.order < 0) ? -ENOMEM : 0; lanai->pci);
return (lanai->aal0buf.start == NULL) ? -ENOMEM : 0;
} }
static inline void aal0_buffer_free(struct lanai_dev *lanai) static inline void aal0_buffer_free(struct lanai_dev *lanai)
{ {
DPRINTK("aal0_buffer_allocate: freeing AAL0 RX buffer\n"); DPRINTK("aal0_buffer_allocate: freeing AAL0 RX buffer\n");
lanai_buf_deallocate(&lanai->aal0buf); lanai_buf_deallocate(&lanai->aal0buf, lanai->pci);
} }
/* -------------------- EEPROM UTILITIES: */ /* -------------------- EEPROM UTILITIES: */
...@@ -1678,36 +1667,37 @@ static inline struct lanai_vcc *new_lanai_vcc(void) ...@@ -1678,36 +1667,37 @@ static inline struct lanai_vcc *new_lanai_vcc(void)
return lvcc; return lvcc;
} }
static int lanai_get_sized_buffer(int number, struct lanai_buffer *buf, static int lanai_get_sized_buffer(struct lanai_dev *lanai,
int max_sdu, int multiplier, int min, const char *name) struct lanai_buffer *buf, int max_sdu, int multiplier,
int min, const char *name)
{ {
int size; int size;
if (max_sdu < 1) if (max_sdu < 1)
max_sdu = 1; max_sdu = 1;
max_sdu = aal5_size(max_sdu); max_sdu = aal5_size(max_sdu);
size = (max_sdu + 16) * multiplier + 16; size = (max_sdu + 16) * multiplier + 16;
lanai_buf_allocate(buf, size, min); lanai_buf_allocate(buf, size, min, lanai->pci);
if (buf->order < 0) if (buf->start == NULL)
return -ENOMEM; return -ENOMEM;
if (lanai_buf_size(buf) < size) if (lanai_buf_size(buf) < size)
printk(KERN_WARNING DEV_LABEL "(itf %d): wanted %d bytes " printk(KERN_WARNING DEV_LABEL "(itf %d): wanted %d bytes "
"for %s buffer, got only %d\n", number, size, name, "for %s buffer, got only %d\n", lanai->number, size, name,
lanai_buf_size(buf)); lanai_buf_size(buf));
DPRINTK("Allocated %d byte %s buffer\n", lanai_buf_size(buf), name); DPRINTK("Allocated %d byte %s buffer\n", lanai_buf_size(buf), name);
return 0; return 0;
} }
/* Setup a RX buffer for a currently unbound AAL5 vci */ /* Setup a RX buffer for a currently unbound AAL5 vci */
static inline int lanai_setup_rx_vci_aal5(int number, struct lanai_vcc *lvcc, static inline int lanai_setup_rx_vci_aal5(struct lanai_dev *lanai,
const struct atm_qos *qos) struct lanai_vcc *lvcc, const struct atm_qos *qos)
{ {
return lanai_get_sized_buffer(number, &lvcc->rx.buf, return lanai_get_sized_buffer(lanai, &lvcc->rx.buf,
qos->rxtp.max_sdu, AAL5_RX_MULTIPLIER, qos->rxtp.max_sdu + 32, qos->rxtp.max_sdu, AAL5_RX_MULTIPLIER, qos->rxtp.max_sdu + 32,
"RX"); "RX");
} }
/* Setup a TX buffer for a currently unbound AAL5 vci */ /* Setup a TX buffer for a currently unbound AAL5 vci */
static int lanai_setup_tx_vci(int number, struct lanai_vcc *lvcc, static int lanai_setup_tx_vci(struct lanai_dev *lanai, struct lanai_vcc *lvcc,
const struct atm_qos *qos) const struct atm_qos *qos)
{ {
int max_sdu, multiplier; int max_sdu, multiplier;
...@@ -1720,7 +1710,7 @@ static int lanai_setup_tx_vci(int number, struct lanai_vcc *lvcc, ...@@ -1720,7 +1710,7 @@ static int lanai_setup_tx_vci(int number, struct lanai_vcc *lvcc,
max_sdu = qos->txtp.max_sdu; max_sdu = qos->txtp.max_sdu;
multiplier = AAL5_TX_MULTIPLIER; multiplier = AAL5_TX_MULTIPLIER;
} }
return lanai_get_sized_buffer(number, &lvcc->tx.buf, max_sdu, return lanai_get_sized_buffer(lanai, &lvcc->tx.buf, max_sdu,
multiplier, 80, "TX"); multiplier, 80, "TX");
} }
...@@ -1781,8 +1771,9 @@ static void lanai_reset(struct lanai_dev *lanai) ...@@ -1781,8 +1771,9 @@ static void lanai_reset(struct lanai_dev *lanai)
*/ */
static int __init service_buffer_allocate(struct lanai_dev *lanai) static int __init service_buffer_allocate(struct lanai_dev *lanai)
{ {
lanai_buf_allocate(&lanai->service, SERVICE_ENTRIES * 4, 0); lanai_buf_allocate(&lanai->service, SERVICE_ENTRIES * 4, 8,
if (lanai->service.order < 0) lanai->pci);
if (lanai->service.start == NULL)
return -ENOMEM; return -ENOMEM;
DPRINTK("allocated service buffer at 0x%08lX, size %d(%d)\n", DPRINTK("allocated service buffer at 0x%08lX, size %d(%d)\n",
(unsigned long) lanai->service.start, (unsigned long) lanai->service.start,
...@@ -1793,14 +1784,14 @@ static int __init service_buffer_allocate(struct lanai_dev *lanai) ...@@ -1793,14 +1784,14 @@ static int __init service_buffer_allocate(struct lanai_dev *lanai)
/* ServiceStuff register contains size and address of buffer */ /* ServiceStuff register contains size and address of buffer */
reg_write(lanai, reg_write(lanai,
SSTUFF_SET_SIZE(lanai_buf_size_cardorder(&lanai->service)) | SSTUFF_SET_SIZE(lanai_buf_size_cardorder(&lanai->service)) |
SSTUFF_SET_ADDR(lanai_buf_dmaaddr(&lanai->service)), SSTUFF_SET_ADDR(lanai->service.dmaaddr),
ServiceStuff_Reg); ServiceStuff_Reg);
return 0; return 0;
} }
static inline void service_buffer_deallocate(struct lanai_dev *lanai) static inline void service_buffer_deallocate(struct lanai_dev *lanai)
{ {
lanai_buf_deallocate(&lanai->service); lanai_buf_deallocate(&lanai->service, lanai->pci);
} }
/* Bitfields in service list */ /* Bitfields in service list */
...@@ -2098,11 +2089,28 @@ static int check_board_id_and_rev(const char *name, u32 val, int *revp) ...@@ -2098,11 +2089,28 @@ static int check_board_id_and_rev(const char *name, u32 val, int *revp)
/* -------------------- PCI INITIALIZATION/SHUTDOWN: */ /* -------------------- PCI INITIALIZATION/SHUTDOWN: */
static inline int __init lanai_pci_start(struct lanai_dev *lanai) static int __init lanai_pci_start(struct lanai_dev *lanai)
{ {
struct pci_dev *pci = lanai->pci; struct pci_dev *pci = lanai->pci;
int result; int result;
u16 w; u16 w;
if (pci_enable_device(pci) != 0) {
printk(KERN_ERR DEV_LABEL "(itf %d): can't enable "
"PCI device", lanai->number);
return -ENXIO;
}
pci_set_master(pci);
if (pci_set_dma_mask(pci, 0xFFFFFFFF) != 0) {
printk(KERN_WARNING DEV_LABEL
"(itf %d): No suitable DMA available.\n", lanai->number);
return -EBUSY;
}
if (pci_set_consistent_dma_mask(pci, 0xFFFFFFFF) != 0) {
printk(KERN_WARNING DEV_LABEL
"(itf %d): No suitable DMA available.\n", lanai->number);
return -EBUSY;
}
/* Get the pci revision byte */ /* Get the pci revision byte */
result = pci_read_config_byte(pci, PCI_REVISION_ID, result = pci_read_config_byte(pci, PCI_REVISION_ID,
&lanai->pci_revision); &lanai->pci_revision);
...@@ -2113,7 +2121,8 @@ static inline int __init lanai_pci_start(struct lanai_dev *lanai) ...@@ -2113,7 +2121,8 @@ static inline int __init lanai_pci_start(struct lanai_dev *lanai)
} }
result = pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &w); result = pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &w);
if (result != PCIBIOS_SUCCESSFUL) { if (result != PCIBIOS_SUCCESSFUL) {
printk(KERN_ERR DEV_LABEL "(itf %d): can't read PCI_SUBSYSTEM_ID: %d\n", lanai->number, result); printk(KERN_ERR DEV_LABEL "(itf %d): can't read "
"PCI_SUBSYSTEM_ID: %d\n", lanai->number, result);
return -EINVAL; return -EINVAL;
} }
if ((result = check_board_id_and_rev("PCI", w, NULL)) != 0) if ((result = check_board_id_and_rev("PCI", w, NULL)) != 0)
...@@ -2125,43 +2134,11 @@ static inline int __init lanai_pci_start(struct lanai_dev *lanai) ...@@ -2125,43 +2134,11 @@ static inline int __init lanai_pci_start(struct lanai_dev *lanai)
"PCI_LATENCY_TIMER: %d\n", lanai->number, result); "PCI_LATENCY_TIMER: %d\n", lanai->number, result);
return -EINVAL; return -EINVAL;
} }
result = pci_read_config_word(pci, PCI_COMMAND, &w);
if (result != PCIBIOS_SUCCESSFUL) {
printk(KERN_ERR DEV_LABEL "(itf %d): can't read "
"PCI_COMMAND: %d\n", lanai->number, result);
return -EINVAL;
}
w |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_SERR |
PCI_COMMAND_PARITY);
result = pci_write_config_word(pci, PCI_COMMAND, w);
if (result != PCIBIOS_SUCCESSFUL) {
printk(KERN_ERR DEV_LABEL "(itf %d): can't "
"write PCI_COMMAND: %d\n", lanai->number, result);
return -EINVAL;
}
pcistatus_check(lanai, 1); pcistatus_check(lanai, 1);
pcistatus_check(lanai, 0); pcistatus_check(lanai, 0);
return 0; return 0;
} }
static void lanai_pci_stop(struct lanai_dev *lanai)
{
struct pci_dev *pci = lanai->pci;
int result;
u16 pci_command;
result = pci_read_config_word(pci, PCI_COMMAND, &pci_command);
if (result != PCIBIOS_SUCCESSFUL) {
printk(KERN_ERR DEV_LABEL "(itf %d): can't "
"read PCI_COMMAND: %d\n", lanai->number, result);
return;
}
pci_command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
result = pci_write_config_word(pci, PCI_COMMAND, pci_command);
if (result != PCIBIOS_SUCCESSFUL)
printk(KERN_ERR DEV_LABEL "(itf %d): can't "
"write PCI_COMMAND: %d\n", lanai->number, result);
}
/* -------------------- VPI/VCI ALLOCATION: */ /* -------------------- VPI/VCI ALLOCATION: */
/* /*
...@@ -2445,7 +2422,7 @@ static int __init lanai_dev_open(struct atm_dev *atmdev) ...@@ -2445,7 +2422,7 @@ static int __init lanai_dev_open(struct atm_dev *atmdev)
#endif #endif
iounmap((void *) lanai->base); iounmap((void *) lanai->base);
error_pci: error_pci:
lanai_pci_stop(lanai); pci_disable_device(lanai->pci);
error: error:
return result; return result;
} }
...@@ -2470,7 +2447,7 @@ static void lanai_dev_close(struct atm_dev *atmdev) ...@@ -2470,7 +2447,7 @@ static void lanai_dev_close(struct atm_dev *atmdev)
lanai->conf1 |= CONFIG1_POWERDOWN; lanai->conf1 |= CONFIG1_POWERDOWN;
conf1_write(lanai); conf1_write(lanai);
#endif #endif
lanai_pci_stop(lanai); pci_disable_device(lanai->pci);
vcc_table_deallocate(lanai); vcc_table_deallocate(lanai);
service_buffer_deallocate(lanai); service_buffer_deallocate(lanai);
iounmap((void *) lanai->base); iounmap((void *) lanai->base);
...@@ -2493,7 +2470,7 @@ static void lanai_close(struct atm_vcc *atmvcc) ...@@ -2493,7 +2470,7 @@ static void lanai_close(struct atm_vcc *atmvcc)
if (--lanai->naal0 <= 0) if (--lanai->naal0 <= 0)
aal0_buffer_free(lanai); aal0_buffer_free(lanai);
} else } else
lanai_buf_deallocate(&lvcc->rx.buf); lanai_buf_deallocate(&lvcc->rx.buf, lanai->pci);
lvcc->rx.atmvcc = NULL; lvcc->rx.atmvcc = NULL;
} }
if (lvcc->tx.atmvcc == atmvcc) { if (lvcc->tx.atmvcc == atmvcc) {
...@@ -2503,7 +2480,7 @@ static void lanai_close(struct atm_vcc *atmvcc) ...@@ -2503,7 +2480,7 @@ static void lanai_close(struct atm_vcc *atmvcc)
lanai->cbrvcc = NULL; lanai->cbrvcc = NULL;
} }
lanai_shutdown_tx_vci(lanai, lvcc); lanai_shutdown_tx_vci(lanai, lvcc);
lanai_buf_deallocate(&lvcc->tx.buf); lanai_buf_deallocate(&lvcc->tx.buf, lanai->pci);
lvcc->tx.atmvcc = NULL; lvcc->tx.atmvcc = NULL;
} }
if (--lvcc->nref == 0) { if (--lvcc->nref == 0) {
...@@ -2551,7 +2528,7 @@ static int lanai_open(struct atm_vcc *atmvcc, short vpi, int vci) ...@@ -2551,7 +2528,7 @@ static int lanai_open(struct atm_vcc *atmvcc, short vpi, int vci)
result = aal0_buffer_allocate(lanai); result = aal0_buffer_allocate(lanai);
} else } else
result = lanai_setup_rx_vci_aal5( result = lanai_setup_rx_vci_aal5(
lanai->number, lvcc, &atmvcc->qos); lanai, lvcc, &atmvcc->qos);
if (result != 0) if (result != 0)
goto out_free; goto out_free;
lvcc->rx.atmvcc = atmvcc; lvcc->rx.atmvcc = atmvcc;
...@@ -2566,7 +2543,7 @@ static int lanai_open(struct atm_vcc *atmvcc, short vpi, int vci) ...@@ -2566,7 +2543,7 @@ static int lanai_open(struct atm_vcc *atmvcc, short vpi, int vci)
if (atmvcc->qos.txtp.traffic_class != ATM_NONE) { if (atmvcc->qos.txtp.traffic_class != ATM_NONE) {
APRINTK(lvcc->tx.atmvcc == NULL, "tx.atmvcc!=NULL, vci=%d\n", APRINTK(lvcc->tx.atmvcc == NULL, "tx.atmvcc!=NULL, vci=%d\n",
vci); vci);
result = lanai_setup_tx_vci(lanai->number, lvcc, &atmvcc->qos); result = lanai_setup_tx_vci(lanai, lvcc, &atmvcc->qos);
if (result != 0) if (result != 0)
goto out_free; goto out_free;
lvcc->tx.atmvcc = atmvcc; lvcc->tx.atmvcc = atmvcc;
...@@ -2849,49 +2826,69 @@ static const struct atmdev_ops ops = { ...@@ -2849,49 +2826,69 @@ static const struct atmdev_ops ops = {
.proc_read = lanai_proc_read .proc_read = lanai_proc_read
}; };
/* detect one type of card LANAI2 or LANAIHB */ /* initialize one probed card */
static int __init lanai_detect_1(unsigned int vendor, unsigned int device) static int __devinit lanai_init_one(struct pci_dev *pci,
const struct pci_device_id *ident)
{ {
struct pci_dev *pci = NULL;
struct lanai_dev *lanai; struct lanai_dev *lanai;
struct atm_dev *atmdev; struct atm_dev *atmdev;
int count = 0, result; int result;
while ((pci = pci_find_device(vendor, device, pci)) != NULL) {
lanai = (struct lanai_dev *) lanai = (struct lanai_dev *) kmalloc(sizeof(*lanai), GFP_KERNEL);
kmalloc(sizeof *lanai, GFP_KERNEL);
if (lanai == NULL) { if (lanai == NULL) {
printk(KERN_ERR DEV_LABEL ": couldn't allocate " printk(KERN_ERR DEV_LABEL
"dev_data structure!\n"); ": couldn't allocate dev_data structure!\n");
break; return -ENOMEM;
} }
atmdev = atm_dev_register(DEV_LABEL, &ops, -1, 0); atmdev = atm_dev_register(DEV_LABEL, &ops, -1, 0);
if (atmdev == NULL) { if (atmdev == NULL) {
printk(KERN_ERR DEV_LABEL ": couldn't register " printk(KERN_ERR DEV_LABEL
"atm device!\n"); ": couldn't register atm device!\n");
kfree(lanai); kfree(lanai);
break; return -EBUSY;
} }
atmdev->dev_data = lanai; atmdev->dev_data = lanai;
lanai->pci = pci; lanai->pci = pci;
lanai->type = (enum lanai_type) device; lanai->type = (enum lanai_type) ident->device;
if ((result = lanai_dev_open(atmdev)) != 0) {
result = lanai_dev_open(atmdev);
if (result != 0) {
DPRINTK("lanai_start() failed, err=%d\n", -result); DPRINTK("lanai_start() failed, err=%d\n", -result);
atm_dev_deregister(atmdev); atm_dev_deregister(atmdev);
kfree(lanai); kfree(lanai);
continue;
}
count++;
} }
return count; return result;
} }
static struct pci_device_id lanai_pci_tbl[] __devinitdata = {
{
PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAI2,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0
},
{
PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAIHB,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0
},
{ 0, } /* terminal entry */
};
MODULE_DEVICE_TABLE(pci, lanai_pci_tbl);
static struct pci_driver lanai_driver = {
.name = DEV_LABEL,
.id_table = lanai_pci_tbl,
.probe = lanai_init_one,
};
static int __init lanai_module_init(void) static int __init lanai_module_init(void)
{ {
if (lanai_detect_1(PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAI2) + int x;
lanai_detect_1(PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAIHB))
return 0; x = pci_module_init(&lanai_driver);
printk(KERN_ERR DEV_LABEL ": no adaptor found\n"); if (x != 0)
return -ENODEV; printk(KERN_ERR DEV_LABEL ": no adapter found\n");
return x;
} }
static void __exit lanai_module_exit(void) static void __exit lanai_module_exit(void)
......
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