Commit a6b5c5dc authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-5.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial fixes from Greg KH:
 "Here are some small serial driver fixes, and a larger number of GSM
  line discipline fixes for 5.18-rc5.

  These include:

   - lots of tiny n_gsm fixes for issues to resolve a number of reported
     problems. Seems that people are starting to actually use this code
     again.

   - 8250 driver fixes for some devices

   - imx serial driver fix

   - amba-pl011 driver fix

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'tty-5.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (27 commits)
  tty: n_gsm: fix sometimes uninitialized warning in gsm_dlci_modem_output()
  serial: 8250: Correct the clock for EndRun PTP/1588 PCIe device
  serial: 8250: Also set sticky MCR bits in console restoration
  tty: n_gsm: fix software flow control handling
  tty: n_gsm: fix invalid use of MSC in advanced option
  tty: n_gsm: fix broken virtual tty handling
  Revert "serial: sc16is7xx: Clear RS485 bits in the shutdown"
  tty: n_gsm: fix missing update of modem controls after DLCI open
  serial: 8250: Fix runtime PM for start_tx() for empty buffer
  serial: imx: fix overrun interrupts in DMA mode
  serial: amba-pl011: do not time out prematurely when draining tx fifo
  tty: n_gsm: fix incorrect UA handling
  tty: n_gsm: fix reset fifo race condition
  tty: n_gsm: fix missing tty wakeup in convergence layer type 2
  tty: n_gsm: fix wrong signal octets encoding in MSC
  tty: n_gsm: fix wrong command frame length field encoding
  tty: n_gsm: fix wrong command retry handling
  tty: n_gsm: fix missing explicit ldisc flush
  tty: n_gsm: fix wrong DLCI release order
  tty: n_gsm: fix insufficient txframe size
  ...
parents da1b4042 19317433
...@@ -73,6 +73,8 @@ module_param(debug, int, 0600); ...@@ -73,6 +73,8 @@ module_param(debug, int, 0600);
*/ */
#define MAX_MRU 1500 #define MAX_MRU 1500
#define MAX_MTU 1500 #define MAX_MTU 1500
/* SOF, ADDR, CTRL, LEN1, LEN2, ..., FCS, EOF */
#define PROT_OVERHEAD 7
#define GSM_NET_TX_TIMEOUT (HZ*10) #define GSM_NET_TX_TIMEOUT (HZ*10)
/* /*
...@@ -219,7 +221,6 @@ struct gsm_mux { ...@@ -219,7 +221,6 @@ struct gsm_mux {
int encoding; int encoding;
u8 control; u8 control;
u8 fcs; u8 fcs;
u8 received_fcs;
u8 *txframe; /* TX framing buffer */ u8 *txframe; /* TX framing buffer */
/* Method for the receiver side */ /* Method for the receiver side */
...@@ -231,6 +232,7 @@ struct gsm_mux { ...@@ -231,6 +232,7 @@ struct gsm_mux {
int initiator; /* Did we initiate connection */ int initiator; /* Did we initiate connection */
bool dead; /* Has the mux been shut down */ bool dead; /* Has the mux been shut down */
struct gsm_dlci *dlci[NUM_DLCI]; struct gsm_dlci *dlci[NUM_DLCI];
int old_c_iflag; /* termios c_iflag value before attach */
bool constipated; /* Asked by remote to shut up */ bool constipated; /* Asked by remote to shut up */
spinlock_t tx_lock; spinlock_t tx_lock;
...@@ -271,10 +273,6 @@ static DEFINE_SPINLOCK(gsm_mux_lock); ...@@ -271,10 +273,6 @@ static DEFINE_SPINLOCK(gsm_mux_lock);
static struct tty_driver *gsm_tty_driver; static struct tty_driver *gsm_tty_driver;
/* Save dlci open address */
static int addr_open[256] = { 0 };
/* Save dlci open count */
static int addr_cnt;
/* /*
* This section of the driver logic implements the GSM encodings * This section of the driver logic implements the GSM encodings
* both the basic and the 'advanced'. Reliable transport is not * both the basic and the 'advanced'. Reliable transport is not
...@@ -369,6 +367,7 @@ static const u8 gsm_fcs8[256] = { ...@@ -369,6 +367,7 @@ static const u8 gsm_fcs8[256] = {
#define GOOD_FCS 0xCF #define GOOD_FCS 0xCF
static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len); static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk);
/** /**
* gsm_fcs_add - update FCS * gsm_fcs_add - update FCS
...@@ -832,7 +831,7 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci) ...@@ -832,7 +831,7 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
break; break;
case 2: /* Unstructed with modem bits. case 2: /* Unstructed with modem bits.
Always one byte as we never send inline break data */ Always one byte as we never send inline break data */
*dp++ = gsm_encode_modem(dlci); *dp++ = (gsm_encode_modem(dlci) << 1) | EA;
break; break;
} }
WARN_ON(kfifo_out_locked(&dlci->fifo, dp , len, &dlci->lock) != len); WARN_ON(kfifo_out_locked(&dlci->fifo, dp , len, &dlci->lock) != len);
...@@ -916,6 +915,66 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, ...@@ -916,6 +915,66 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
return size; return size;
} }
/**
* gsm_dlci_modem_output - try and push modem status out of a DLCI
* @gsm: mux
* @dlci: the DLCI to pull modem status from
* @brk: break signal
*
* Push an empty frame in to the transmit queue to update the modem status
* bits and to transmit an optional break.
*
* Caller must hold the tx_lock of the mux.
*/
static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci,
u8 brk)
{
u8 *dp = NULL;
struct gsm_msg *msg;
int size = 0;
/* for modem bits without break data */
switch (dlci->adaption) {
case 1: /* Unstructured */
break;
case 2: /* Unstructured with modem bits. */
size++;
if (brk > 0)
size++;
break;
default:
pr_err("%s: unsupported adaption %d\n", __func__,
dlci->adaption);
return -EINVAL;
}
msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
if (!msg) {
pr_err("%s: gsm_data_alloc error", __func__);
return -ENOMEM;
}
dp = msg->data;
switch (dlci->adaption) {
case 1: /* Unstructured */
break;
case 2: /* Unstructured with modem bits. */
if (brk == 0) {
*dp++ = (gsm_encode_modem(dlci) << 1) | EA;
} else {
*dp++ = gsm_encode_modem(dlci) << 1;
*dp++ = (brk << 4) | 2 | EA; /* Length, Break, EA */
}
break;
default:
/* Handled above */
break;
}
__gsm_data_queue(dlci, msg);
return size;
}
/** /**
* gsm_dlci_data_sweep - look for data to send * gsm_dlci_data_sweep - look for data to send
* @gsm: the GSM mux * @gsm: the GSM mux
...@@ -1093,7 +1152,6 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen) ...@@ -1093,7 +1152,6 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
{ {
unsigned int addr = 0; unsigned int addr = 0;
unsigned int modem = 0; unsigned int modem = 0;
unsigned int brk = 0;
struct gsm_dlci *dlci; struct gsm_dlci *dlci;
int len = clen; int len = clen;
int slen; int slen;
...@@ -1123,17 +1181,8 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen) ...@@ -1123,17 +1181,8 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
return; return;
} }
len--; len--;
if (len > 0) {
while (gsm_read_ea(&brk, *dp++) == 0) {
len--;
if (len == 0)
return;
}
modem <<= 7;
modem |= (brk & 0x7f);
}
tty = tty_port_tty_get(&dlci->port); tty = tty_port_tty_get(&dlci->port);
gsm_process_modem(tty, dlci, modem, slen); gsm_process_modem(tty, dlci, modem, slen - len);
if (tty) { if (tty) {
tty_wakeup(tty); tty_wakeup(tty);
tty_kref_put(tty); tty_kref_put(tty);
...@@ -1193,7 +1242,6 @@ static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen) ...@@ -1193,7 +1242,6 @@ static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen)
} }
static void gsm_dlci_begin_close(struct gsm_dlci *dlci); static void gsm_dlci_begin_close(struct gsm_dlci *dlci);
static void gsm_dlci_close(struct gsm_dlci *dlci);
/** /**
* gsm_control_message - DLCI 0 control processing * gsm_control_message - DLCI 0 control processing
...@@ -1212,28 +1260,15 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, ...@@ -1212,28 +1260,15 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
{ {
u8 buf[1]; u8 buf[1];
unsigned long flags; unsigned long flags;
struct gsm_dlci *dlci;
int i;
int address;
switch (command) { switch (command) {
case CMD_CLD: { case CMD_CLD: {
if (addr_cnt > 0) { struct gsm_dlci *dlci = gsm->dlci[0];
for (i = 0; i < addr_cnt; i++) {
address = addr_open[i];
dlci = gsm->dlci[address];
gsm_dlci_close(dlci);
addr_open[i] = 0;
}
}
/* Modem wishes to close down */ /* Modem wishes to close down */
dlci = gsm->dlci[0];
if (dlci) { if (dlci) {
dlci->dead = true; dlci->dead = true;
gsm->dead = true; gsm->dead = true;
gsm_dlci_close(dlci); gsm_dlci_begin_close(dlci);
addr_cnt = 0;
gsm_response(gsm, 0, UA|PF);
} }
} }
break; break;
...@@ -1326,11 +1361,12 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command, ...@@ -1326,11 +1361,12 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl) static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl)
{ {
struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1, gsm->ftype); struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 2, gsm->ftype);
if (msg == NULL) if (msg == NULL)
return; return;
msg->data[0] = (ctrl->cmd << 1) | 2 | EA; /* command */ msg->data[0] = (ctrl->cmd << 1) | CR | EA; /* command */
memcpy(msg->data + 1, ctrl->data, ctrl->len); msg->data[1] = (ctrl->len << 1) | EA;
memcpy(msg->data + 2, ctrl->data, ctrl->len);
gsm_data_queue(gsm->dlci[0], msg); gsm_data_queue(gsm->dlci[0], msg);
} }
...@@ -1353,7 +1389,6 @@ static void gsm_control_retransmit(struct timer_list *t) ...@@ -1353,7 +1389,6 @@ static void gsm_control_retransmit(struct timer_list *t)
spin_lock_irqsave(&gsm->control_lock, flags); spin_lock_irqsave(&gsm->control_lock, flags);
ctrl = gsm->pending_cmd; ctrl = gsm->pending_cmd;
if (ctrl) { if (ctrl) {
gsm->cretries--;
if (gsm->cretries == 0) { if (gsm->cretries == 0) {
gsm->pending_cmd = NULL; gsm->pending_cmd = NULL;
ctrl->error = -ETIMEDOUT; ctrl->error = -ETIMEDOUT;
...@@ -1362,6 +1397,7 @@ static void gsm_control_retransmit(struct timer_list *t) ...@@ -1362,6 +1397,7 @@ static void gsm_control_retransmit(struct timer_list *t)
wake_up(&gsm->event); wake_up(&gsm->event);
return; return;
} }
gsm->cretries--;
gsm_control_transmit(gsm, ctrl); gsm_control_transmit(gsm, ctrl);
mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100); mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100);
} }
...@@ -1402,7 +1438,7 @@ static struct gsm_control *gsm_control_send(struct gsm_mux *gsm, ...@@ -1402,7 +1438,7 @@ static struct gsm_control *gsm_control_send(struct gsm_mux *gsm,
/* If DLCI0 is in ADM mode skip retries, it won't respond */ /* If DLCI0 is in ADM mode skip retries, it won't respond */
if (gsm->dlci[0]->mode == DLCI_MODE_ADM) if (gsm->dlci[0]->mode == DLCI_MODE_ADM)
gsm->cretries = 1; gsm->cretries = 0;
else else
gsm->cretries = gsm->n2; gsm->cretries = gsm->n2;
...@@ -1450,20 +1486,22 @@ static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control) ...@@ -1450,20 +1486,22 @@ static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
static void gsm_dlci_close(struct gsm_dlci *dlci) static void gsm_dlci_close(struct gsm_dlci *dlci)
{ {
unsigned long flags;
del_timer(&dlci->t1); del_timer(&dlci->t1);
if (debug & 8) if (debug & 8)
pr_debug("DLCI %d goes closed.\n", dlci->addr); pr_debug("DLCI %d goes closed.\n", dlci->addr);
dlci->state = DLCI_CLOSED; dlci->state = DLCI_CLOSED;
if (dlci->addr != 0) { if (dlci->addr != 0) {
tty_port_tty_hangup(&dlci->port, false); tty_port_tty_hangup(&dlci->port, false);
spin_lock_irqsave(&dlci->lock, flags);
kfifo_reset(&dlci->fifo); kfifo_reset(&dlci->fifo);
spin_unlock_irqrestore(&dlci->lock, flags);
/* Ensure that gsmtty_open() can return. */ /* Ensure that gsmtty_open() can return. */
tty_port_set_initialized(&dlci->port, 0); tty_port_set_initialized(&dlci->port, 0);
wake_up_interruptible(&dlci->port.open_wait); wake_up_interruptible(&dlci->port.open_wait);
} else } else
dlci->gsm->dead = true; dlci->gsm->dead = true;
/* Unregister gsmtty driver,report gsmtty dev remove uevent for user */
tty_unregister_device(gsm_tty_driver, dlci->addr);
wake_up(&dlci->gsm->event); wake_up(&dlci->gsm->event);
/* A DLCI 0 close is a MUX termination so we need to kick that /* A DLCI 0 close is a MUX termination so we need to kick that
back to userspace somehow */ back to userspace somehow */
...@@ -1485,8 +1523,9 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) ...@@ -1485,8 +1523,9 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
dlci->state = DLCI_OPEN; dlci->state = DLCI_OPEN;
if (debug & 8) if (debug & 8)
pr_debug("DLCI %d goes open.\n", dlci->addr); pr_debug("DLCI %d goes open.\n", dlci->addr);
/* Register gsmtty driver,report gsmtty dev add uevent for user */ /* Send current modem state */
tty_register_device(gsm_tty_driver, dlci->addr, NULL); if (dlci->addr)
gsm_modem_update(dlci, 0);
wake_up(&dlci->gsm->event); wake_up(&dlci->gsm->event);
} }
...@@ -1623,6 +1662,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen) ...@@ -1623,6 +1662,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
tty = tty_port_tty_get(port); tty = tty_port_tty_get(port);
if (tty) { if (tty) {
gsm_process_modem(tty, dlci, modem, slen); gsm_process_modem(tty, dlci, modem, slen);
tty_wakeup(tty);
tty_kref_put(tty); tty_kref_put(tty);
} }
fallthrough; fallthrough;
...@@ -1793,19 +1833,7 @@ static void gsm_queue(struct gsm_mux *gsm) ...@@ -1793,19 +1833,7 @@ static void gsm_queue(struct gsm_mux *gsm)
struct gsm_dlci *dlci; struct gsm_dlci *dlci;
u8 cr; u8 cr;
int address; int address;
int i, j, k, address_tmp;
/* We have to sneak a look at the packet body to do the FCS.
A somewhat layering violation in the spec */
if ((gsm->control & ~PF) == UI)
gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
if (gsm->encoding == 0) {
/* WARNING: gsm->received_fcs is used for
gsm->encoding = 0 only.
In this case it contain the last piece of data
required to generate final CRC */
gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
}
if (gsm->fcs != GOOD_FCS) { if (gsm->fcs != GOOD_FCS) {
gsm->bad_fcs++; gsm->bad_fcs++;
if (debug & 4) if (debug & 4)
...@@ -1836,11 +1864,6 @@ static void gsm_queue(struct gsm_mux *gsm) ...@@ -1836,11 +1864,6 @@ static void gsm_queue(struct gsm_mux *gsm)
else { else {
gsm_response(gsm, address, UA|PF); gsm_response(gsm, address, UA|PF);
gsm_dlci_open(dlci); gsm_dlci_open(dlci);
/* Save dlci open address */
if (address) {
addr_open[addr_cnt] = address;
addr_cnt++;
}
} }
break; break;
case DISC|PF: case DISC|PF:
...@@ -1851,35 +1874,9 @@ static void gsm_queue(struct gsm_mux *gsm) ...@@ -1851,35 +1874,9 @@ static void gsm_queue(struct gsm_mux *gsm)
return; return;
} }
/* Real close complete */ /* Real close complete */
if (!address) { gsm_response(gsm, address, UA|PF);
if (addr_cnt > 0) { gsm_dlci_close(dlci);
for (i = 0; i < addr_cnt; i++) {
address = addr_open[i];
dlci = gsm->dlci[address];
gsm_dlci_close(dlci);
addr_open[i] = 0;
}
}
dlci = gsm->dlci[0];
gsm_dlci_close(dlci);
addr_cnt = 0;
gsm_response(gsm, 0, UA|PF);
} else {
gsm_response(gsm, address, UA|PF);
gsm_dlci_close(dlci);
/* clear dlci address */
for (j = 0; j < addr_cnt; j++) {
address_tmp = addr_open[j];
if (address_tmp == address) {
for (k = j; k < addr_cnt; k++)
addr_open[k] = addr_open[k+1];
addr_cnt--;
break;
}
}
}
break; break;
case UA:
case UA|PF: case UA|PF:
if (cr == 0 || dlci == NULL) if (cr == 0 || dlci == NULL)
break; break;
...@@ -1993,19 +1990,25 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) ...@@ -1993,19 +1990,25 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
break; break;
case GSM_DATA: /* Data */ case GSM_DATA: /* Data */
gsm->buf[gsm->count++] = c; gsm->buf[gsm->count++] = c;
if (gsm->count == gsm->len) if (gsm->count == gsm->len) {
/* Calculate final FCS for UI frames over all data */
if ((gsm->control & ~PF) != UIH) {
gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
gsm->count);
}
gsm->state = GSM_FCS; gsm->state = GSM_FCS;
}
break; break;
case GSM_FCS: /* FCS follows the packet */ case GSM_FCS: /* FCS follows the packet */
gsm->received_fcs = c; gsm->fcs = gsm_fcs_add(gsm->fcs, c);
gsm_queue(gsm);
gsm->state = GSM_SSOF; gsm->state = GSM_SSOF;
break; break;
case GSM_SSOF: case GSM_SSOF:
if (c == GSM0_SOF) { gsm->state = GSM_SEARCH;
gsm->state = GSM_SEARCH; if (c == GSM0_SOF)
break; gsm_queue(gsm);
} else
gsm->bad_size++;
break; break;
default: default:
pr_debug("%s: unhandled state: %d\n", __func__, gsm->state); pr_debug("%s: unhandled state: %d\n", __func__, gsm->state);
...@@ -2023,12 +2026,35 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) ...@@ -2023,12 +2026,35 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
{ {
/* handle XON/XOFF */
if ((c & ISO_IEC_646_MASK) == XON) {
gsm->constipated = true;
return;
} else if ((c & ISO_IEC_646_MASK) == XOFF) {
gsm->constipated = false;
/* Kick the link in case it is idling */
gsm_data_kick(gsm, NULL);
return;
}
if (c == GSM1_SOF) { if (c == GSM1_SOF) {
/* EOF is only valid in frame if we have got to the data state /* EOF is only valid in frame if we have got to the data state */
and received at least one byte (the FCS) */ if (gsm->state == GSM_DATA) {
if (gsm->state == GSM_DATA && gsm->count) { if (gsm->count < 1) {
/* Extract the FCS */ /* Missing FSC */
gsm->malformed++;
gsm->state = GSM_START;
return;
}
/* Remove the FCS from data */
gsm->count--; gsm->count--;
if ((gsm->control & ~PF) != UIH) {
/* Calculate final FCS for UI frames over all
* data but FCS
*/
gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
gsm->count);
}
/* Add the FCS itself to test against GOOD_FCS */
gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]); gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
gsm->len = gsm->count; gsm->len = gsm->count;
gsm_queue(gsm); gsm_queue(gsm);
...@@ -2037,7 +2063,8 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) ...@@ -2037,7 +2063,8 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
} }
/* Any partial frame was a runt so go back to start */ /* Any partial frame was a runt so go back to start */
if (gsm->state != GSM_START) { if (gsm->state != GSM_START) {
gsm->malformed++; if (gsm->state != GSM_SEARCH)
gsm->malformed++;
gsm->state = GSM_START; gsm->state = GSM_START;
} }
/* A SOF in GSM_START means we are still reading idling or /* A SOF in GSM_START means we are still reading idling or
...@@ -2106,74 +2133,43 @@ static void gsm_error(struct gsm_mux *gsm) ...@@ -2106,74 +2133,43 @@ static void gsm_error(struct gsm_mux *gsm)
gsm->io_error++; gsm->io_error++;
} }
static int gsm_disconnect(struct gsm_mux *gsm)
{
struct gsm_dlci *dlci = gsm->dlci[0];
struct gsm_control *gc;
if (!dlci)
return 0;
/* In theory disconnecting DLCI 0 is sufficient but for some
modems this is apparently not the case. */
gc = gsm_control_send(gsm, CMD_CLD, NULL, 0);
if (gc)
gsm_control_wait(gsm, gc);
del_timer_sync(&gsm->t2_timer);
/* Now we are sure T2 has stopped */
gsm_dlci_begin_close(dlci);
wait_event_interruptible(gsm->event,
dlci->state == DLCI_CLOSED);
if (signal_pending(current))
return -EINTR;
return 0;
}
/** /**
* gsm_cleanup_mux - generic GSM protocol cleanup * gsm_cleanup_mux - generic GSM protocol cleanup
* @gsm: our mux * @gsm: our mux
* @disc: disconnect link?
* *
* Clean up the bits of the mux which are the same for all framing * Clean up the bits of the mux which are the same for all framing
* protocols. Remove the mux from the mux table, stop all the timers * protocols. Remove the mux from the mux table, stop all the timers
* and then shut down each device hanging up the channels as we go. * and then shut down each device hanging up the channels as we go.
*/ */
static void gsm_cleanup_mux(struct gsm_mux *gsm) static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
{ {
int i; int i;
struct gsm_dlci *dlci = gsm->dlci[0]; struct gsm_dlci *dlci = gsm->dlci[0];
struct gsm_msg *txq, *ntxq; struct gsm_msg *txq, *ntxq;
gsm->dead = true; gsm->dead = true;
mutex_lock(&gsm->mutex);
spin_lock(&gsm_mux_lock); if (dlci) {
for (i = 0; i < MAX_MUX; i++) { if (disc && dlci->state != DLCI_CLOSED) {
if (gsm_mux[i] == gsm) { gsm_dlci_begin_close(dlci);
gsm_mux[i] = NULL; wait_event(gsm->event, dlci->state == DLCI_CLOSED);
break;
} }
dlci->dead = true;
} }
spin_unlock(&gsm_mux_lock);
/* open failed before registering => nothing to do */
if (i == MAX_MUX)
return;
/* Finish outstanding timers, making sure they are done */
del_timer_sync(&gsm->t2_timer); del_timer_sync(&gsm->t2_timer);
/* Now we are sure T2 has stopped */
if (dlci)
dlci->dead = true;
/* Free up any link layer users */ /* Free up any link layer users and finally the control channel */
mutex_lock(&gsm->mutex); for (i = NUM_DLCI - 1; i >= 0; i--)
for (i = 0; i < NUM_DLCI; i++)
if (gsm->dlci[i]) if (gsm->dlci[i])
gsm_dlci_release(gsm->dlci[i]); gsm_dlci_release(gsm->dlci[i]);
mutex_unlock(&gsm->mutex); mutex_unlock(&gsm->mutex);
/* Now wipe the queues */ /* Now wipe the queues */
tty_ldisc_flush(gsm->tty);
list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list) list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
kfree(txq); kfree(txq);
INIT_LIST_HEAD(&gsm->tx_list); INIT_LIST_HEAD(&gsm->tx_list);
...@@ -2191,7 +2187,6 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm) ...@@ -2191,7 +2187,6 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm)
static int gsm_activate_mux(struct gsm_mux *gsm) static int gsm_activate_mux(struct gsm_mux *gsm)
{ {
struct gsm_dlci *dlci; struct gsm_dlci *dlci;
int i = 0;
timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0);
init_waitqueue_head(&gsm->event); init_waitqueue_head(&gsm->event);
...@@ -2203,18 +2198,6 @@ static int gsm_activate_mux(struct gsm_mux *gsm) ...@@ -2203,18 +2198,6 @@ static int gsm_activate_mux(struct gsm_mux *gsm)
else else
gsm->receive = gsm1_receive; gsm->receive = gsm1_receive;
spin_lock(&gsm_mux_lock);
for (i = 0; i < MAX_MUX; i++) {
if (gsm_mux[i] == NULL) {
gsm->num = i;
gsm_mux[i] = gsm;
break;
}
}
spin_unlock(&gsm_mux_lock);
if (i == MAX_MUX)
return -EBUSY;
dlci = gsm_dlci_alloc(gsm, 0); dlci = gsm_dlci_alloc(gsm, 0);
if (dlci == NULL) if (dlci == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -2230,6 +2213,15 @@ static int gsm_activate_mux(struct gsm_mux *gsm) ...@@ -2230,6 +2213,15 @@ static int gsm_activate_mux(struct gsm_mux *gsm)
*/ */
static void gsm_free_mux(struct gsm_mux *gsm) static void gsm_free_mux(struct gsm_mux *gsm)
{ {
int i;
for (i = 0; i < MAX_MUX; i++) {
if (gsm == gsm_mux[i]) {
gsm_mux[i] = NULL;
break;
}
}
mutex_destroy(&gsm->mutex);
kfree(gsm->txframe); kfree(gsm->txframe);
kfree(gsm->buf); kfree(gsm->buf);
kfree(gsm); kfree(gsm);
...@@ -2249,12 +2241,20 @@ static void gsm_free_muxr(struct kref *ref) ...@@ -2249,12 +2241,20 @@ static void gsm_free_muxr(struct kref *ref)
static inline void mux_get(struct gsm_mux *gsm) static inline void mux_get(struct gsm_mux *gsm)
{ {
unsigned long flags;
spin_lock_irqsave(&gsm_mux_lock, flags);
kref_get(&gsm->ref); kref_get(&gsm->ref);
spin_unlock_irqrestore(&gsm_mux_lock, flags);
} }
static inline void mux_put(struct gsm_mux *gsm) static inline void mux_put(struct gsm_mux *gsm)
{ {
unsigned long flags;
spin_lock_irqsave(&gsm_mux_lock, flags);
kref_put(&gsm->ref, gsm_free_muxr); kref_put(&gsm->ref, gsm_free_muxr);
spin_unlock_irqrestore(&gsm_mux_lock, flags);
} }
static inline unsigned int mux_num_to_base(struct gsm_mux *gsm) static inline unsigned int mux_num_to_base(struct gsm_mux *gsm)
...@@ -2275,6 +2275,7 @@ static inline unsigned int mux_line_to_num(unsigned int line) ...@@ -2275,6 +2275,7 @@ static inline unsigned int mux_line_to_num(unsigned int line)
static struct gsm_mux *gsm_alloc_mux(void) static struct gsm_mux *gsm_alloc_mux(void)
{ {
int i;
struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL); struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
if (gsm == NULL) if (gsm == NULL)
return NULL; return NULL;
...@@ -2283,7 +2284,7 @@ static struct gsm_mux *gsm_alloc_mux(void) ...@@ -2283,7 +2284,7 @@ static struct gsm_mux *gsm_alloc_mux(void)
kfree(gsm); kfree(gsm);
return NULL; return NULL;
} }
gsm->txframe = kmalloc(2 * MAX_MRU + 2, GFP_KERNEL); gsm->txframe = kmalloc(2 * (MAX_MTU + PROT_OVERHEAD - 1), GFP_KERNEL);
if (gsm->txframe == NULL) { if (gsm->txframe == NULL) {
kfree(gsm->buf); kfree(gsm->buf);
kfree(gsm); kfree(gsm);
...@@ -2304,6 +2305,26 @@ static struct gsm_mux *gsm_alloc_mux(void) ...@@ -2304,6 +2305,26 @@ static struct gsm_mux *gsm_alloc_mux(void)
gsm->mtu = 64; gsm->mtu = 64;
gsm->dead = true; /* Avoid early tty opens */ gsm->dead = true; /* Avoid early tty opens */
/* Store the instance to the mux array or abort if no space is
* available.
*/
spin_lock(&gsm_mux_lock);
for (i = 0; i < MAX_MUX; i++) {
if (!gsm_mux[i]) {
gsm_mux[i] = gsm;
gsm->num = i;
break;
}
}
spin_unlock(&gsm_mux_lock);
if (i == MAX_MUX) {
mutex_destroy(&gsm->mutex);
kfree(gsm->txframe);
kfree(gsm->buf);
kfree(gsm);
return NULL;
}
return gsm; return gsm;
} }
...@@ -2339,7 +2360,7 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c) ...@@ -2339,7 +2360,7 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
/* Check the MRU/MTU range looks sane */ /* Check the MRU/MTU range looks sane */
if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8) if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
return -EINVAL; return -EINVAL;
if (c->n2 < 3) if (c->n2 > 255)
return -EINVAL; return -EINVAL;
if (c->encapsulation > 1) /* Basic, advanced, no I */ if (c->encapsulation > 1) /* Basic, advanced, no I */
return -EINVAL; return -EINVAL;
...@@ -2370,19 +2391,11 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c) ...@@ -2370,19 +2391,11 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
/* /*
* Close down what is needed, restart and initiate the new * Close down what is needed, restart and initiate the new
* configuration * configuration. On the first time there is no DLCI[0]
* and closing or cleaning up is not necessary.
*/ */
if (need_close || need_restart)
if (gsm->initiator && (need_close || need_restart)) { gsm_cleanup_mux(gsm, true);
int ret;
ret = gsm_disconnect(gsm);
if (ret)
return ret;
}
if (need_restart)
gsm_cleanup_mux(gsm);
gsm->initiator = c->initiator; gsm->initiator = c->initiator;
gsm->mru = c->mru; gsm->mru = c->mru;
...@@ -2450,25 +2463,26 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) ...@@ -2450,25 +2463,26 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
int ret, i; int ret, i;
gsm->tty = tty_kref_get(tty); gsm->tty = tty_kref_get(tty);
/* Turn off tty XON/XOFF handling to handle it explicitly. */
gsm->old_c_iflag = tty->termios.c_iflag;
tty->termios.c_iflag &= (IXON | IXOFF);
ret = gsm_activate_mux(gsm); ret = gsm_activate_mux(gsm);
if (ret != 0) if (ret != 0)
tty_kref_put(gsm->tty); tty_kref_put(gsm->tty);
else { else {
/* Don't register device 0 - this is the control channel and not /* Don't register device 0 - this is the control channel and not
a usable tty interface */ a usable tty interface */
if (gsm->initiator) { base = mux_num_to_base(gsm); /* Base for this MUX */
base = mux_num_to_base(gsm); /* Base for this MUX */ for (i = 1; i < NUM_DLCI; i++) {
for (i = 1; i < NUM_DLCI; i++) { struct device *dev;
struct device *dev;
dev = tty_register_device(gsm_tty_driver, dev = tty_register_device(gsm_tty_driver,
base + i, NULL); base + i, NULL);
if (IS_ERR(dev)) { if (IS_ERR(dev)) {
for (i--; i >= 1; i--) for (i--; i >= 1; i--)
tty_unregister_device(gsm_tty_driver, tty_unregister_device(gsm_tty_driver,
base + i); base + i);
return PTR_ERR(dev); return PTR_ERR(dev);
}
} }
} }
} }
...@@ -2490,11 +2504,10 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) ...@@ -2490,11 +2504,10 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
int i; int i;
WARN_ON(tty != gsm->tty); WARN_ON(tty != gsm->tty);
if (gsm->initiator) { for (i = 1; i < NUM_DLCI; i++)
for (i = 1; i < NUM_DLCI; i++) tty_unregister_device(gsm_tty_driver, base + i);
tty_unregister_device(gsm_tty_driver, base + i); /* Restore tty XON/XOFF handling. */
} gsm->tty->termios.c_iflag = gsm->old_c_iflag;
gsm_cleanup_mux(gsm);
tty_kref_put(gsm->tty); tty_kref_put(gsm->tty);
gsm->tty = NULL; gsm->tty = NULL;
} }
...@@ -2559,6 +2572,12 @@ static void gsmld_close(struct tty_struct *tty) ...@@ -2559,6 +2572,12 @@ static void gsmld_close(struct tty_struct *tty)
{ {
struct gsm_mux *gsm = tty->disc_data; struct gsm_mux *gsm = tty->disc_data;
/* The ldisc locks and closes the port before calling our close. This
* means we have no way to do a proper disconnect. We will not bother
* to do one.
*/
gsm_cleanup_mux(gsm, false);
gsmld_detach_gsm(tty, gsm); gsmld_detach_gsm(tty, gsm);
gsmld_flush_buffer(tty); gsmld_flush_buffer(tty);
...@@ -2597,7 +2616,7 @@ static int gsmld_open(struct tty_struct *tty) ...@@ -2597,7 +2616,7 @@ static int gsmld_open(struct tty_struct *tty)
ret = gsmld_attach_gsm(tty, gsm); ret = gsmld_attach_gsm(tty, gsm);
if (ret != 0) { if (ret != 0) {
gsm_cleanup_mux(gsm); gsm_cleanup_mux(gsm, false);
mux_put(gsm); mux_put(gsm);
} }
return ret; return ret;
...@@ -2954,26 +2973,78 @@ static struct tty_ldisc_ops tty_ldisc_packet = { ...@@ -2954,26 +2973,78 @@ static struct tty_ldisc_ops tty_ldisc_packet = {
#define TX_SIZE 512 #define TX_SIZE 512
static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk) /**
* gsm_modem_upd_via_data - send modem bits via convergence layer
* @dlci: channel
* @brk: break signal
*
* Send an empty frame to signal mobile state changes and to transmit the
* break signal for adaption 2.
*/
static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk)
{ {
u8 modembits[5]; struct gsm_mux *gsm = dlci->gsm;
unsigned long flags;
if (dlci->state != DLCI_OPEN || dlci->adaption != 2)
return;
spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_dlci_modem_output(gsm, dlci, brk);
spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
/**
* gsm_modem_upd_via_msc - send modem bits via control frame
* @dlci: channel
* @brk: break signal
*/
static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk)
{
u8 modembits[3];
struct gsm_control *ctrl; struct gsm_control *ctrl;
int len = 2; int len = 2;
if (brk) if (dlci->gsm->encoding != 0)
len++; return 0;
modembits[0] = len << 1 | EA; /* Data bytes */ modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */
modembits[1] = dlci->addr << 2 | 3; /* DLCI, EA, 1 */ if (!brk) {
modembits[2] = gsm_encode_modem(dlci) << 1 | EA; modembits[1] = (gsm_encode_modem(dlci) << 1) | EA;
if (brk) } else {
modembits[3] = brk << 4 | 2 | EA; /* Valid, EA */ modembits[1] = gsm_encode_modem(dlci) << 1;
ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len + 1); modembits[2] = (brk << 4) | 2 | EA; /* Length, Break, EA */
len++;
}
ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len);
if (ctrl == NULL) if (ctrl == NULL)
return -ENOMEM; return -ENOMEM;
return gsm_control_wait(dlci->gsm, ctrl); return gsm_control_wait(dlci->gsm, ctrl);
} }
/**
* gsm_modem_update - send modem status line state
* @dlci: channel
* @brk: break signal
*/
static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk)
{
if (dlci->adaption == 2) {
/* Send convergence layer type 2 empty data frame. */
gsm_modem_upd_via_data(dlci, brk);
return 0;
} else if (dlci->gsm->encoding == 0) {
/* Send as MSC control message. */
return gsm_modem_upd_via_msc(dlci, brk);
}
/* Modem status lines are not supported. */
return -EPROTONOSUPPORT;
}
static int gsm_carrier_raised(struct tty_port *port) static int gsm_carrier_raised(struct tty_port *port)
{ {
struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port); struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port);
...@@ -3006,7 +3077,7 @@ static void gsm_dtr_rts(struct tty_port *port, int onoff) ...@@ -3006,7 +3077,7 @@ static void gsm_dtr_rts(struct tty_port *port, int onoff)
modem_tx &= ~(TIOCM_DTR | TIOCM_RTS); modem_tx &= ~(TIOCM_DTR | TIOCM_RTS);
if (modem_tx != dlci->modem_tx) { if (modem_tx != dlci->modem_tx) {
dlci->modem_tx = modem_tx; dlci->modem_tx = modem_tx;
gsmtty_modem_update(dlci, 0); gsm_modem_update(dlci, 0);
} }
} }
...@@ -3155,13 +3226,17 @@ static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty) ...@@ -3155,13 +3226,17 @@ static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty)
static void gsmtty_flush_buffer(struct tty_struct *tty) static void gsmtty_flush_buffer(struct tty_struct *tty)
{ {
struct gsm_dlci *dlci = tty->driver_data; struct gsm_dlci *dlci = tty->driver_data;
unsigned long flags;
if (dlci->state == DLCI_CLOSED) if (dlci->state == DLCI_CLOSED)
return; return;
/* Caution needed: If we implement reliable transport classes /* Caution needed: If we implement reliable transport classes
then the data being transmitted can't simply be junked once then the data being transmitted can't simply be junked once
it has first hit the stack. Until then we can just blow it it has first hit the stack. Until then we can just blow it
away */ away */
spin_lock_irqsave(&dlci->lock, flags);
kfifo_reset(&dlci->fifo); kfifo_reset(&dlci->fifo);
spin_unlock_irqrestore(&dlci->lock, flags);
/* Need to unhook this DLCI from the transmit queue logic */ /* Need to unhook this DLCI from the transmit queue logic */
} }
...@@ -3193,7 +3268,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty, ...@@ -3193,7 +3268,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
if (modem_tx != dlci->modem_tx) { if (modem_tx != dlci->modem_tx) {
dlci->modem_tx = modem_tx; dlci->modem_tx = modem_tx;
return gsmtty_modem_update(dlci, 0); return gsm_modem_update(dlci, 0);
} }
return 0; return 0;
} }
...@@ -3254,7 +3329,7 @@ static void gsmtty_throttle(struct tty_struct *tty) ...@@ -3254,7 +3329,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
dlci->modem_tx &= ~TIOCM_RTS; dlci->modem_tx &= ~TIOCM_RTS;
dlci->throttled = true; dlci->throttled = true;
/* Send an MSC with RTS cleared */ /* Send an MSC with RTS cleared */
gsmtty_modem_update(dlci, 0); gsm_modem_update(dlci, 0);
} }
static void gsmtty_unthrottle(struct tty_struct *tty) static void gsmtty_unthrottle(struct tty_struct *tty)
...@@ -3266,7 +3341,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty) ...@@ -3266,7 +3341,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
dlci->modem_tx |= TIOCM_RTS; dlci->modem_tx |= TIOCM_RTS;
dlci->throttled = false; dlci->throttled = false;
/* Send an MSC with RTS set */ /* Send an MSC with RTS set */
gsmtty_modem_update(dlci, 0); gsm_modem_update(dlci, 0);
} }
static int gsmtty_break_ctl(struct tty_struct *tty, int state) static int gsmtty_break_ctl(struct tty_struct *tty, int state)
...@@ -3284,7 +3359,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state) ...@@ -3284,7 +3359,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
if (encode > 0x0F) if (encode > 0x0F)
encode = 0x0F; /* Best effort */ encode = 0x0F; /* Best effort */
} }
return gsmtty_modem_update(dlci, encode); return gsm_modem_update(dlci, encode);
} }
static void gsmtty_cleanup(struct tty_struct *tty) static void gsmtty_cleanup(struct tty_struct *tty)
......
...@@ -2667,7 +2667,7 @@ enum pci_board_num_t { ...@@ -2667,7 +2667,7 @@ enum pci_board_num_t {
pbn_panacom2, pbn_panacom2,
pbn_panacom4, pbn_panacom4,
pbn_plx_romulus, pbn_plx_romulus,
pbn_endrun_2_4000000, pbn_endrun_2_3906250,
pbn_oxsemi, pbn_oxsemi,
pbn_oxsemi_1_3906250, pbn_oxsemi_1_3906250,
pbn_oxsemi_2_3906250, pbn_oxsemi_2_3906250,
...@@ -3195,10 +3195,10 @@ static struct pciserial_board pci_boards[] = { ...@@ -3195,10 +3195,10 @@ static struct pciserial_board pci_boards[] = {
* signal now many ports are available * signal now many ports are available
* 2 port 952 Uart support * 2 port 952 Uart support
*/ */
[pbn_endrun_2_4000000] = { [pbn_endrun_2_3906250] = {
.flags = FL_BASE0, .flags = FL_BASE0,
.num_ports = 2, .num_ports = 2,
.base_baud = 4000000, .base_baud = 3906250,
.uart_offset = 0x200, .uart_offset = 0x200,
.first_offset = 0x1000, .first_offset = 0x1000,
}, },
...@@ -4115,7 +4115,7 @@ static const struct pci_device_id serial_pci_tbl[] = { ...@@ -4115,7 +4115,7 @@ static const struct pci_device_id serial_pci_tbl[] = {
*/ */
{ PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588, { PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_endrun_2_4000000 }, pbn_endrun_2_3906250 },
/* /*
* Quatech cards. These actually have configurable clocks but for * Quatech cards. These actually have configurable clocks but for
* now we just use the default. * now we just use the default.
......
...@@ -1675,11 +1675,11 @@ static void serial8250_start_tx(struct uart_port *port) ...@@ -1675,11 +1675,11 @@ static void serial8250_start_tx(struct uart_port *port)
struct uart_8250_port *up = up_to_u8250p(port); struct uart_8250_port *up = up_to_u8250p(port);
struct uart_8250_em485 *em485 = up->em485; struct uart_8250_em485 *em485 = up->em485;
serial8250_rpm_get_tx(up);
if (!port->x_char && uart_circ_empty(&port->state->xmit)) if (!port->x_char && uart_circ_empty(&port->state->xmit))
return; return;
serial8250_rpm_get_tx(up);
if (em485 && if (em485 &&
em485->active_timer == &em485->start_tx_timer) em485->active_timer == &em485->start_tx_timer)
return; return;
...@@ -3329,7 +3329,7 @@ static void serial8250_console_restore(struct uart_8250_port *up) ...@@ -3329,7 +3329,7 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_set_divisor(port, baud, quot, frac); serial8250_set_divisor(port, baud, quot, frac);
serial_port_out(port, UART_LCR, up->lcr); serial_port_out(port, UART_LCR, up->lcr);
serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS); serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
} }
/* /*
......
...@@ -1255,13 +1255,18 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) ...@@ -1255,13 +1255,18 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
static void pl011_rs485_tx_stop(struct uart_amba_port *uap) static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
{ {
/*
* To be on the safe side only time out after twice as many iterations
* as fifo size.
*/
const int MAX_TX_DRAIN_ITERS = uap->port.fifosize * 2;
struct uart_port *port = &uap->port; struct uart_port *port = &uap->port;
int i = 0; int i = 0;
u32 cr; u32 cr;
/* Wait until hardware tx queue is empty */ /* Wait until hardware tx queue is empty */
while (!pl011_tx_empty(port)) { while (!pl011_tx_empty(port)) {
if (i == port->fifosize) { if (i > MAX_TX_DRAIN_ITERS) {
dev_warn(port->dev, dev_warn(port->dev,
"timeout while draining hardware tx queue\n"); "timeout while draining hardware tx queue\n");
break; break;
...@@ -2052,7 +2057,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, ...@@ -2052,7 +2057,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
* with the given baud rate. We use this as the poll interval when we * with the given baud rate. We use this as the poll interval when we
* wait for the tx queue to empty. * wait for the tx queue to empty.
*/ */
uap->rs485_tx_drain_interval = (bits * 1000 * 1000) / baud; uap->rs485_tx_drain_interval = DIV_ROUND_UP(bits * 1000 * 1000, baud);
pl011_setup_status_masks(port, termios); pl011_setup_status_masks(port, termios);
......
...@@ -1448,7 +1448,7 @@ static int imx_uart_startup(struct uart_port *port) ...@@ -1448,7 +1448,7 @@ static int imx_uart_startup(struct uart_port *port)
imx_uart_writel(sport, ucr1, UCR1); imx_uart_writel(sport, ucr1, UCR1);
ucr4 = imx_uart_readl(sport, UCR4) & ~(UCR4_OREN | UCR4_INVR); ucr4 = imx_uart_readl(sport, UCR4) & ~(UCR4_OREN | UCR4_INVR);
if (!sport->dma_is_enabled) if (!dma_is_inited)
ucr4 |= UCR4_OREN; ucr4 |= UCR4_OREN;
if (sport->inverted_rx) if (sport->inverted_rx)
ucr4 |= UCR4_INVR; ucr4 |= UCR4_INVR;
......
...@@ -1238,12 +1238,10 @@ static void sc16is7xx_shutdown(struct uart_port *port) ...@@ -1238,12 +1238,10 @@ static void sc16is7xx_shutdown(struct uart_port *port)
/* Disable all interrupts */ /* Disable all interrupts */
sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0);
/* Disable TX/RX, clear auto RS485 and RTS invert */ /* Disable TX/RX */
sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG,
SC16IS7XX_EFCR_RXDISABLE_BIT | SC16IS7XX_EFCR_RXDISABLE_BIT |
SC16IS7XX_EFCR_TXDISABLE_BIT | SC16IS7XX_EFCR_TXDISABLE_BIT,
SC16IS7XX_EFCR_AUTO_RS485_BIT |
SC16IS7XX_EFCR_RTS_INVERT_BIT,
SC16IS7XX_EFCR_RXDISABLE_BIT | SC16IS7XX_EFCR_RXDISABLE_BIT |
SC16IS7XX_EFCR_TXDISABLE_BIT); SC16IS7XX_EFCR_TXDISABLE_BIT);
......
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