Commit 43eef00a authored by Paul Fulghum's avatar Paul Fulghum Committed by Linus Torvalds

[PATCH] synclinkmp transmit eom fix

Bug Fixes:

* Fix transmit end of message (EOM) processing to work correctly with
  hardware auto CTS feature

* Fix oops in error path if hardware diags fail during device
  initialization

Cosmetic change:

* Use existing macros for address space size instead of hardcoded values
Signed-off-by: default avatarPaul Fulghum <paulkf@microgate.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent a3f5b14e
/*
* $Id: synclinkmp.c,v 4.26 2004/08/11 19:30:02 paulkf Exp $
* $Id: synclinkmp.c,v 4.29 2004/08/27 20:06:41 paulkf Exp $
*
* Device driver for Microgate SyncLink Multiport
* high speed multiprotocol serial adapter.
......@@ -489,7 +489,7 @@ MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICES) "i");
MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i");
static char *driver_name = "SyncLink MultiPort driver";
static char *driver_version = "$Revision: 4.26 $";
static char *driver_version = "$Revision: 4.29 $";
static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent);
static void synclinkmp_remove_one(struct pci_dev *dev);
......@@ -651,7 +651,7 @@ static unsigned char tx_active_fifo_level = 16; // tx request FIFO activation le
static unsigned char tx_negate_fifo_level = 32; // tx request FIFO negation level in bytes
static u32 misc_ctrl_value = 0x007e4040;
static u32 lcr1_brdr_value = 0x0080002d;
static u32 lcr1_brdr_value = 0x00800029;
static u32 read_ahead_count = 8;
......@@ -2182,16 +2182,15 @@ void isr_rxint(SLMP_INFO * info)
{
struct tty_struct *tty = info->tty;
struct mgsl_icount *icount = &info->icount;
unsigned char status = read_reg(info, SR1);
unsigned char status2 = read_reg(info, SR2);
unsigned char status = read_reg(info, SR1) & info->ie1_value & (FLGD + IDLD + CDCD + BRKD);
unsigned char status2 = read_reg(info, SR2) & info->ie2_value & OVRN;
/* clear status bits */
if ( status & (FLGD + IDLD + CDCD + BRKD) )
write_reg(info, SR1,
(unsigned char)(status & (FLGD + IDLD + CDCD + BRKD)));
if (status)
write_reg(info, SR1, status);
if ( status2 & OVRN )
write_reg(info, SR2, (unsigned char)(status2 & OVRN));
if (status2)
write_reg(info, SR2, status2);
if ( debug_level >= DEBUG_LEVEL_ISR )
printk("%s(%d):%s isr_rxint status=%02X %02x\n",
......@@ -2328,15 +2327,22 @@ void isr_txeom(SLMP_INFO * info, unsigned char status)
printk("%s(%d):%s isr_txeom status=%02x\n",
__FILE__,__LINE__,info->device_name,status);
/* disable and clear MSCI interrupts */
info->ie1_value &= ~(IDLE + UDRN);
write_reg(info, IE1, info->ie1_value);
write_reg(info, SR1, (unsigned char)(UDRN + IDLE));
write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */
write_reg(info, TXDMA + DSR, 0xc0); /* clear IRQs and disable DMA */
write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */
if (status & UDRN) {
write_reg(info, CMD, TXRESET);
write_reg(info, CMD, TXENABLE);
} else
write_reg(info, CMD, TXBUFCLR);
/* disable and clear tx interrupts */
info->ie0_value &= ~TXRDYE;
info->ie1_value &= ~(IDLE + UDRN);
write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value));
write_reg(info, SR1, (unsigned char)(UDRN + IDLE));
if ( info->tx_active ) {
if (info->params.mode != MGSL_MODE_ASYNC) {
if (status & UDRN)
......@@ -2377,10 +2383,10 @@ void isr_txeom(SLMP_INFO * info, unsigned char status)
*/
void isr_txint(SLMP_INFO * info)
{
unsigned char status = read_reg(info, SR1);
unsigned char status = read_reg(info, SR1) & info->ie1_value & (UDRN + IDLE + CCTS);
/* clear status bits */
write_reg(info, SR1, (unsigned char)(status & (UDRN + IDLE + CCTS)));
write_reg(info, SR1, status);
if ( debug_level >= DEBUG_LEVEL_ISR )
printk("%s(%d):%s isr_txint status=%02x\n",
......@@ -2409,6 +2415,14 @@ void isr_txrdy(SLMP_INFO * info)
printk("%s(%d):%s isr_txrdy() tx_count=%d\n",
__FILE__,__LINE__,info->device_name,info->tx_count);
if (info->params.mode != MGSL_MODE_ASYNC) {
/* disable TXRDY IRQ, enable IDLE IRQ */
info->ie0_value &= ~TXRDYE;
info->ie1_value |= IDLE;
write_reg16(info, IE0, (unsigned short)((info->ie1_value << 8) + info->ie0_value));
return;
}
if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {
tx_stop(info);
return;
......@@ -2463,13 +2477,6 @@ void isr_rxdmaerror(SLMP_INFO * info)
void isr_txdmaok(SLMP_INFO * info)
{
/* BIT7 = EOT (end of transfer, used for async mode)
* BIT6 = EOM (end of message/frame, used for sync mode)
*
* We don't look at DMA status because only EOT is enabled
* and we always clear and disable all tx DMA IRQs.
*/
// unsigned char dma_status = read_reg(info,TXDMA + DSR) & 0xc0;
unsigned char status_reg1 = read_reg(info, SR1);
write_reg(info, TXDMA + DIR, 0x00); /* disable Tx DMA IRQs */
......@@ -2480,19 +2487,10 @@ void isr_txdmaok(SLMP_INFO * info)
printk("%s(%d):%s isr_txdmaok(), status=%02x\n",
__FILE__,__LINE__,info->device_name,status_reg1);
/* If transmitter already idle, do end of frame processing,
* otherwise enable interrupt for tx IDLE.
*/
if (status_reg1 & IDLE)
isr_txeom(info, IDLE);
else {
/* disable and clear underrun IRQ, enable IDLE interrupt */
info->ie1_value |= IDLE;
info->ie1_value &= ~UDRN;
write_reg(info, IE1, info->ie1_value);
write_reg(info, SR1, UDRN);
}
/* program TXRDY as FIFO empty flag, enable TXRDY IRQ */
write_reg16(info, TRC0, 0);
info->ie0_value |= TXRDYE;
write_reg(info, IE0, info->ie0_value);
}
void isr_txdmaerror(SLMP_INFO * info)
......@@ -3176,7 +3174,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr)
unsigned char oldval = info->ie1_value;
unsigned char newval = oldval +
(mask & MgslEvent_ExitHuntMode ? FLGD:0) +
(mask & MgslEvent_IdleReceived ? IDLE:0);
(mask & MgslEvent_IdleReceived ? IDLD:0);
if ( oldval != newval ) {
info->ie1_value = newval;
write_reg(info, IE1, info->ie1_value);
......@@ -3243,7 +3241,7 @@ static int wait_mgsl_event(SLMP_INFO * info, int __user *mask_ptr)
spin_lock_irqsave(&info->lock,flags);
if (!waitqueue_active(&info->event_wait_q)) {
/* disable enable exit hunt mode/idle rcvd IRQs */
info->ie1_value &= ~(FLGD|IDLE);
info->ie1_value &= ~(FLGD|IDLD);
write_reg(info, IE1, info->ie1_value);
}
spin_unlock_irqrestore(&info->lock,flags);
......@@ -3637,9 +3635,10 @@ void free_tmp_rx_buf(SLMP_INFO *info)
int claim_resources(SLMP_INFO *info)
{
if (request_mem_region(info->phys_memory_base,0x40000,"synclinkmp") == NULL) {
if (request_mem_region(info->phys_memory_base,SCA_MEM_SIZE,"synclinkmp") == NULL) {
printk( "%s(%d):%s mem addr conflict, Addr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base);
info->init_error = DiagStatus_AddressConflict;
goto errout;
}
else
......@@ -3648,22 +3647,25 @@ int claim_resources(SLMP_INFO *info)
if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclinkmp") == NULL) {
printk( "%s(%d):%s lcr mem addr conflict, Addr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base);
info->init_error = DiagStatus_AddressConflict;
goto errout;
}
else
info->lcr_mem_requested = 1;
if (request_mem_region(info->phys_sca_base + info->sca_offset,512,"synclinkmp") == NULL) {
if (request_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE,"synclinkmp") == NULL) {
printk( "%s(%d):%s sca mem addr conflict, Addr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_sca_base);
info->init_error = DiagStatus_AddressConflict;
goto errout;
}
else
info->sca_base_requested = 1;
if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,16,"synclinkmp") == NULL) {
if (request_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE,"synclinkmp") == NULL) {
printk( "%s(%d):%s stat/ctrl mem addr conflict, Addr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_statctrl_base);
info->init_error = DiagStatus_AddressConflict;
goto errout;
}
else
......@@ -3673,33 +3675,41 @@ int claim_resources(SLMP_INFO *info)
if (!info->memory_base) {
printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
info->init_error = DiagStatus_CantAssignPciResources;
goto errout;
}
if ( !memory_test(info) ) {
printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
goto errout;
}
info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset;
info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE);
if (!info->lcr_base) {
printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base );
info->init_error = DiagStatus_CantAssignPciResources;
goto errout;
}
info->lcr_base += info->lcr_offset;
info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE) + info->sca_offset;
info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE);
if (!info->sca_base) {
printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_sca_base );
info->init_error = DiagStatus_CantAssignPciResources;
goto errout;
}
info->sca_base += info->sca_offset;
info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE) + info->statctrl_offset;
info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE);
if (!info->statctrl_base) {
printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_statctrl_base );
info->init_error = DiagStatus_CantAssignPciResources;
goto errout;
}
info->statctrl_base += info->statctrl_offset;
if ( !memory_test(info) ) {
printk( "%s(%d):Shared Memory Test failed for device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
info->init_error = DiagStatus_MemoryError;
goto errout;
}
......@@ -3722,7 +3732,7 @@ void release_resources(SLMP_INFO *info)
}
if ( info->shared_mem_requested ) {
release_mem_region(info->phys_memory_base,0x40000);
release_mem_region(info->phys_memory_base,SCA_MEM_SIZE);
info->shared_mem_requested = 0;
}
if ( info->lcr_mem_requested ) {
......@@ -3730,11 +3740,11 @@ void release_resources(SLMP_INFO *info)
info->lcr_mem_requested = 0;
}
if ( info->sca_base_requested ) {
release_mem_region(info->phys_sca_base + info->sca_offset,512);
release_mem_region(info->phys_sca_base + info->sca_offset,SCA_BASE_SIZE);
info->sca_base_requested = 0;
}
if ( info->sca_statctrl_requested ) {
release_mem_region(info->phys_statctrl_base + info->statctrl_offset,16);
release_mem_region(info->phys_statctrl_base + info->statctrl_offset,SCA_REG_SIZE);
info->sca_statctrl_requested = 0;
}
......@@ -3975,7 +3985,6 @@ static struct tty_operations ops = {
static void synclinkmp_cleanup(void)
{
unsigned long flags;
int rc;
SLMP_INFO *info;
SLMP_INFO *tmp;
......@@ -3989,33 +3998,24 @@ static void synclinkmp_cleanup(void)
put_tty_driver(serial_driver);
}
/* reset devices */
info = synclinkmp_device_list;
while(info) {
#ifdef CONFIG_HDLC
hdlcdev_exit(info);
#endif
reset_port(info);
if ( info->port_num == 0 ) {
if ( info->irq_requested ) {
free_irq(info->irq_level, info);
info->irq_requested = 0;
}
}
info = info->next_device;
}
/* port 0 of each adapter originally claimed
* all resources, release those now
*/
/* release devices */
info = synclinkmp_device_list;
while(info) {
#ifdef CONFIG_HDLC
hdlcdev_exit(info);
#endif
free_dma_bufs(info);
free_tmp_rx_buf(info);
if ( info->port_num == 0 ) {
spin_lock_irqsave(&info->lock,flags);
reset_adapter(info);
write_reg(info, LPR, 1); /* set low power mode */
spin_unlock_irqrestore(&info->lock,flags);
if (info->sca_base)
write_reg(info, LPR, 1); /* set low power mode */
release_resources(info);
}
tmp = info;
......@@ -4298,6 +4298,9 @@ void tx_start(SLMP_INFO *info)
}
}
write_reg16(info, TRC0,
(unsigned short)(((tx_negate_fifo_level-1)<<8) + tx_active_fifo_level));
write_reg(info, TXDMA + DSR, 0); /* disable DMA channel */
write_reg(info, TXDMA + DCMD, SWABORT); /* reset/init DMA channel */
......@@ -4309,11 +4312,10 @@ void tx_start(SLMP_INFO *info)
write_reg16(info, TXDMA + EDA,
info->tx_buf_list_ex[info->last_tx_buf].phys_entry);
/* clear IDLE and UDRN status bit */
info->ie1_value &= ~(IDLE + UDRN);
if (info->params.mode != MGSL_MODE_ASYNC)
info->ie1_value |= UDRN; /* HDLC, IRQ on underrun */
write_reg(info, IE1, info->ie1_value); /* enable MSCI interrupts */
/* enable underrun IRQ */
info->ie1_value &= ~IDLE;
info->ie1_value |= UDRN;
write_reg(info, IE1, info->ie1_value);
write_reg(info, SR1, (unsigned char)(IDLE + UDRN));
write_reg(info, TXDMA + DIR, 0x40); /* enable Tx DMA interrupts (EOM) */
......
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