diff options
Diffstat (limited to 'drivers/tty')
25 files changed, 1112 insertions, 398 deletions
diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 0e32920af10d..7ca3cd8eb574 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -151,7 +151,7 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) address = (unsigned long)(void *)buf; goldfish_tty_rw(qtty, address, count, 0); - tty_schedule_flip(&qtty->port); + tty_flip_buffer_push(&qtty->port); return IRQ_HANDLED; } diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index bf17e90858b8..a29ec5a93839 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1383,7 +1383,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, if (inited && !tty_throttled(tty) && MoxaPortRxQueue(p) > 0) { /* RX */ MoxaPortReadData(p); - tty_schedule_flip(&p->port); + tty_flip_buffer_push(&p->port); } } else { clear_bit(EMPTYWAIT, &p->statusflags); @@ -1408,7 +1408,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */ tty_insert_flip_char(&p->port, 0, TTY_BREAK); - tty_schedule_flip(&p->port); + tty_flip_buffer_push(&p->port); } if (intr & IntrLine) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 6734ef22c304..154697be11b0 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -137,6 +137,7 @@ struct gsm_dlci { int retries; /* Uplink tty if active */ struct tty_port port; /* The tty bound to this DLCI if there is one */ +#define TX_SIZE 4096 /* Must be power of 2. */ struct kfifo fifo; /* Queue fifo for the DLCI */ int adaption; /* Adaption layer in use */ int prev_adaption; @@ -221,7 +222,6 @@ struct gsm_mux { int encoding; u8 control; u8 fcs; - u8 received_fcs; u8 *txframe; /* TX framing buffer */ /* Method for the receiver side */ @@ -235,6 +235,7 @@ struct gsm_mux { 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 has_devices; /* Devices were registered */ spinlock_t tx_lock; unsigned int tx_bytes; /* TX data outstanding */ @@ -243,6 +244,7 @@ struct gsm_mux { struct list_head tx_list; /* Pending data packets */ /* Control messages */ + struct timer_list kick_timer; /* Kick TX queuing on timeout */ struct timer_list t2_timer; /* Retransmit timer for commands */ int cretries; /* Command retry counter */ struct gsm_control *pending_cmd;/* Our current pending command */ @@ -274,6 +276,10 @@ static DEFINE_SPINLOCK(gsm_mux_lock); 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 * both the basic and the 'advanced'. Reliable transport is not @@ -368,6 +374,7 @@ static const u8 gsm_fcs8[256] = { #define GOOD_FCS 0xCF 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 @@ -419,6 +426,27 @@ static int gsm_read_ea(unsigned int *val, u8 c) } /** + * gsm_read_ea_val - read a value until EA + * @val: variable holding value + * @data: buffer of data + * @dlen: length of data + * + * Processes an EA value. Updates the passed variable and + * returns the processed data length. + */ +static unsigned int gsm_read_ea_val(unsigned int *val, const u8 *data, int dlen) +{ + unsigned int len = 0; + + for (; dlen > 0; dlen--) { + len++; + if (gsm_read_ea(val, *data++)) + break; + } + return len; +} + +/** * gsm_encode_modem - encode modem data bits * @dlci: DLCI to encode from * @@ -463,10 +491,72 @@ static void gsm_hex_dump_bytes(const char *fname, const u8 *data, } /** + * gsm_register_devices - register all tty devices for a given mux index + * + * @driver: the tty driver that describes the tty devices + * @index: the mux number is used to calculate the minor numbers of the + * ttys for this mux and may differ from the position in the + * mux array. + */ +static int gsm_register_devices(struct tty_driver *driver, unsigned int index) +{ + struct device *dev; + int i; + unsigned int base; + + if (!driver || index >= MAX_MUX) + return -EINVAL; + + base = index * NUM_DLCI; /* first minor for this index */ + for (i = 1; i < NUM_DLCI; i++) { + /* Don't register device 0 - this is the control channel + * and not a usable tty interface + */ + dev = tty_register_device(gsm_tty_driver, base + i, NULL); + if (IS_ERR(dev)) { + if (debug & 8) + pr_info("%s failed to register device minor %u", + __func__, base + i); + for (i--; i >= 1; i--) + tty_unregister_device(gsm_tty_driver, base + i); + return PTR_ERR(dev); + } + } + + return 0; +} + +/** + * gsm_unregister_devices - unregister all tty devices for a given mux index + * + * @driver: the tty driver that describes the tty devices + * @index: the mux number is used to calculate the minor numbers of the + * ttys for this mux and may differ from the position in the + * mux array. + */ +static void gsm_unregister_devices(struct tty_driver *driver, + unsigned int index) +{ + int i; + unsigned int base; + + if (!driver || index >= MAX_MUX) + return; + + base = index * NUM_DLCI; /* first minor for this index */ + for (i = 1; i < NUM_DLCI; i++) { + /* Don't unregister device 0 - this is the control + * channel and not a usable tty interface + */ + tty_unregister_device(gsm_tty_driver, base + i); + } +} + +/** * gsm_print_packet - display a frame for debug * @hdr: header to print before decode * @addr: address EA from the frame - * @cr: C/R bit from the frame + * @cr: C/R bit seen as initiator * @control: control including PF bit * @data: following data bytes * @dlen: length of data @@ -566,7 +656,7 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len) * gsm_send - send a control frame * @gsm: our GSM mux * @addr: address for control frame - * @cr: command/response bit + * @cr: command/response bit seen as initiator * @control: control byte including PF bit * * Format up and transmit a control frame. These do not go via the @@ -581,11 +671,15 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) int len; u8 cbuf[10]; u8 ibuf[3]; + int ocr; + + /* toggle C/R coding if not initiator */ + ocr = cr ^ (gsm->initiator ? 0 : 1); switch (gsm->encoding) { case 0: cbuf[0] = GSM0_SOF; - cbuf[1] = (addr << 2) | (cr << 1) | EA; + cbuf[1] = (addr << 2) | (ocr << 1) | EA; cbuf[2] = control; cbuf[3] = EA; /* Length of data = 0 */ cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3); @@ -595,7 +689,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control) case 1: case 2: /* Control frame + packing (but not frame stuffing) in mode 1 */ - ibuf[0] = (addr << 2) | (cr << 1) | EA; + ibuf[0] = (addr << 2) | (ocr << 1) | EA; ibuf[1] = control; ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2); /* Stuffing may double the size worst case */ @@ -674,6 +768,37 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, } /** + * gsm_is_flow_ctrl_msg - checks if flow control message + * @msg: message to check + * + * Returns true if the given message is a flow control command of the + * control channel. False is returned in any other case. + */ +static bool gsm_is_flow_ctrl_msg(struct gsm_msg *msg) +{ + unsigned int cmd; + + if (msg->addr > 0) + return false; + + switch (msg->ctrl & ~PF) { + case UI: + case UIH: + cmd = 0; + if (gsm_read_ea_val(&cmd, msg->data + 2, msg->len - 2) < 1) + break; + switch (cmd & ~PF) { + case CMD_FCOFF: + case CMD_FCON: + return true; + } + break; + } + + return false; +} + +/** * gsm_data_kick - poke the queue * @gsm: GSM Mux * @dlci: DLCI sending the data @@ -692,7 +817,7 @@ static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci) int len; list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) { - if (gsm->constipated && msg->addr) + if (gsm->constipated && !gsm_is_flow_ctrl_msg(msg)) continue; if (gsm->encoding != 0) { gsm->txframe[0] = GSM1_SOF; @@ -778,6 +903,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) list_add_tail(&msg->list, &gsm->tx_list); gsm->tx_bytes += msg->len; gsm_data_kick(gsm, dlci); + mod_timer(&gsm->kick_timer, jiffies + 10 * gsm->t1 * HZ / 100); } /** @@ -814,41 +940,48 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci) { struct gsm_msg *msg; u8 *dp; - int len, total_size, size; - int h = dlci->adaption - 1; + int h, len, size; - total_size = 0; - while (1) { - len = kfifo_len(&dlci->fifo); - if (len == 0) - return total_size; - - /* MTU/MRU count only the data bits */ - if (len > gsm->mtu) - len = gsm->mtu; - - size = len + h; - - msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); - /* FIXME: need a timer or something to kick this so it can't - get stuck with no work outstanding and no buffer free */ - if (msg == NULL) - return -ENOMEM; - dp = msg->data; - switch (dlci->adaption) { - case 1: /* Unstructured */ - break; - case 2: /* Unstructed with modem bits. - Always one byte as we never send inline break data */ - *dp++ = (gsm_encode_modem(dlci) << 1) | EA; - break; - } - WARN_ON(kfifo_out_locked(&dlci->fifo, dp , len, &dlci->lock) != len); - __gsm_data_queue(dlci, msg); - total_size += size; + /* for modem bits without break data */ + h = ((dlci->adaption == 1) ? 0 : 1); + + len = kfifo_len(&dlci->fifo); + if (len == 0) + return 0; + + /* MTU/MRU count only the data bits but watch adaption mode */ + if ((len + h) > gsm->mtu) + len = gsm->mtu - h; + + size = len + h; + + msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); + if (!msg) + return -ENOMEM; + dp = msg->data; + switch (dlci->adaption) { + case 1: /* Unstructured */ + break; + case 2: /* Unstructured with modem bits. + * Always one byte as we never send inline break data + */ + *dp++ = (gsm_encode_modem(dlci) << 1) | EA; + break; + default: + pr_err("%s: unsupported adaption %d\n", __func__, + dlci->adaption); + break; } + + WARN_ON(len != kfifo_out_locked(&dlci->fifo, dp, len, + &dlci->lock)); + + /* Notify upper layer about available send space. */ + tty_port_tty_wakeup(&dlci->port); + + __gsm_data_queue(dlci, msg); /* Bytes of data we used up */ - return total_size; + return size; } /** @@ -899,9 +1032,6 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, size = len + overhead; msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); - - /* FIXME: need a timer or something to kick this so it can't - get stuck with no work outstanding and no buffer free */ if (msg == NULL) { skb_queue_tail(&dlci->skb_list, dlci->skb); dlci->skb = NULL; @@ -925,6 +1055,66 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, } /** + * 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: the GSM mux * @@ -937,9 +1127,9 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm, * renegotiate DLCI priorities with optional stuff. Needs optimising. */ -static void gsm_dlci_data_sweep(struct gsm_mux *gsm) +static int gsm_dlci_data_sweep(struct gsm_mux *gsm) { - int len; + int len, ret = 0; /* Priority ordering: We should do priority with RR of the groups */ int i = 1; @@ -962,7 +1152,11 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) /* DLCI empty - try the next */ if (len == 0) i++; + else + ret++; } + + return ret; } /** @@ -1191,6 +1385,7 @@ 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_close(struct gsm_dlci *dlci); /** * gsm_control_message - DLCI 0 control processing @@ -1209,15 +1404,28 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, { u8 buf[1]; unsigned long flags; + struct gsm_dlci *dlci; + int i; + int address; switch (command) { case CMD_CLD: { - struct gsm_dlci *dlci = gsm->dlci[0]; + if (addr_cnt > 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 */ + dlci = gsm->dlci[0]; if (dlci) { dlci->dead = true; gsm->dead = true; - gsm_dlci_begin_close(dlci); + gsm_dlci_close(dlci); + addr_cnt = 0; + gsm_response(gsm, 0, UA|PF); } } break; @@ -1338,7 +1546,7 @@ static void gsm_control_retransmit(struct timer_list *t) spin_lock_irqsave(&gsm->control_lock, flags); ctrl = gsm->pending_cmd; if (ctrl) { - if (gsm->cretries == 0) { + if (gsm->cretries == 0 || !gsm->dlci[0] || gsm->dlci[0]->dead) { gsm->pending_cmd = NULL; ctrl->error = -ETIMEDOUT; ctrl->done = 1; @@ -1441,6 +1649,8 @@ static void gsm_dlci_close(struct gsm_dlci *dlci) if (debug & 8) pr_debug("DLCI %d goes closed.\n", dlci->addr); dlci->state = DLCI_CLOSED; + /* Prevent us from sending data before the link is up again */ + dlci->constipated = true; if (dlci->addr != 0) { tty_port_tty_hangup(&dlci->port, false); spin_lock_irqsave(&dlci->lock, flags); @@ -1470,8 +1680,12 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) del_timer(&dlci->t1); /* This will let a tty open continue */ dlci->state = DLCI_OPEN; + dlci->constipated = false; if (debug & 8) pr_debug("DLCI %d goes open.\n", dlci->addr); + /* Send current modem state */ + if (dlci->addr) + gsm_modem_update(dlci, 0); wake_up(&dlci->gsm->event); } @@ -1497,8 +1711,8 @@ static void gsm_dlci_t1(struct timer_list *t) switch (dlci->state) { case DLCI_OPENING: - dlci->retries--; if (dlci->retries) { + dlci->retries--; gsm_command(dlci->gsm, dlci->addr, SABM|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); } else if (!dlci->addr && gsm->control == (DM | PF)) { @@ -1513,8 +1727,8 @@ static void gsm_dlci_t1(struct timer_list *t) break; case DLCI_CLOSING: - dlci->retries--; if (dlci->retries) { + dlci->retries--; gsm_command(dlci->gsm, dlci->addr, DISC|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); } else @@ -1548,6 +1762,25 @@ static void gsm_dlci_begin_open(struct gsm_dlci *dlci) } /** + * gsm_dlci_set_opening - change state to opening + * @dlci: DLCI to open + * + * Change internal state to wait for DLCI open from initiator side. + * We set off timers and responses upon reception of an SABM. + */ +static void gsm_dlci_set_opening(struct gsm_dlci *dlci) +{ + switch (dlci->state) { + case DLCI_CLOSED: + case DLCI_CLOSING: + dlci->state = DLCI_OPENING; + break; + default: + break; + } +} + +/** * gsm_dlci_begin_close - start channel open procedure * @dlci: DLCI to open * @@ -1656,6 +1889,30 @@ static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len) } } +/** + * gsm_kick_timer - transmit if possible + * @t: timer contained in our gsm object + * + * Transmit data from DLCIs if the queue is empty. We can't rely on + * a tty wakeup except when we filled the pipe so we need to fire off + * new data ourselves in other cases. + */ +static void gsm_kick_timer(struct timer_list *t) +{ + struct gsm_mux *gsm = from_timer(gsm, t, kick_timer); + unsigned long flags; + int sent = 0; + + spin_lock_irqsave(&gsm->tx_lock, flags); + /* If we have nothing running then we need to fire up */ + if (gsm->tx_bytes < TX_THRESH_LO) + sent = gsm_dlci_data_sweep(gsm); + spin_unlock_irqrestore(&gsm->tx_lock, flags); + + if (sent && debug & 4) + pr_info("%s TX queue stalled\n", __func__); +} + /* * Allocate/Free DLCI channels */ @@ -1677,7 +1934,7 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr) return NULL; spin_lock_init(&dlci->lock); mutex_init(&dlci->mutex); - if (kfifo_alloc(&dlci->fifo, 4096, GFP_KERNEL) < 0) { + if (kfifo_alloc(&dlci->fifo, TX_SIZE, GFP_KERNEL) < 0) { kfree(dlci); return NULL; } @@ -1690,10 +1947,13 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr) dlci->addr = addr; dlci->adaption = gsm->adaption; dlci->state = DLCI_CLOSED; - if (addr) + if (addr) { dlci->data = gsm_dlci_data; - else + /* Prevent us from sending data before the link is up */ + dlci->constipated = true; + } else { dlci->data = gsm_dlci_command; + } gsm->dlci[addr] = dlci; return dlci; } @@ -1780,18 +2040,8 @@ static void gsm_queue(struct gsm_mux *gsm) struct gsm_dlci *dlci; u8 cr; int address; - /* We have to sneak a look at the packet body to do the FCS. - A somewhat layering violation in the spec */ + int i, j, k, address_tmp; - 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) { gsm->bad_fcs++; if (debug & 4) @@ -1803,10 +2053,10 @@ static void gsm_queue(struct gsm_mux *gsm) goto invalid; cr = gsm->address & 1; /* C/R bit */ + cr ^= gsm->initiator ? 0 : 1; /* Flip so 1 always means command */ gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len); - cr ^= 1 - gsm->initiator; /* Flip so 1 always means command */ dlci = gsm->dlci[address]; switch (gsm->control) { @@ -1818,22 +2068,52 @@ static void gsm_queue(struct gsm_mux *gsm) if (dlci == NULL) return; if (dlci->dead) - gsm_response(gsm, address, DM); + gsm_response(gsm, address, DM|PF); else { - gsm_response(gsm, address, UA); + gsm_response(gsm, address, UA|PF); gsm_dlci_open(dlci); + /* Save dlci open address */ + if (address) { + addr_open[addr_cnt] = address; + addr_cnt++; + } } break; case DISC|PF: if (cr == 0) goto invalid; if (dlci == NULL || dlci->state == DLCI_CLOSED) { - gsm_response(gsm, address, DM); + gsm_response(gsm, address, DM|PF); return; } /* Real close complete */ - gsm_response(gsm, address, UA); - gsm_dlci_close(dlci); + if (!address) { + if (addr_cnt > 0) { + 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; case UA|PF: if (cr == 0 || dlci == NULL) @@ -1868,7 +2148,7 @@ static void gsm_queue(struct gsm_mux *gsm) goto invalid; #endif if (dlci == NULL || dlci->state != DLCI_OPEN) { - gsm_command(gsm, address, DM|PF); + gsm_response(gsm, address, DM|PF); return; } dlci->data(dlci, gsm->buf, gsm->len); @@ -1948,19 +2228,25 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c) break; case GSM_DATA: /* Data */ 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; + } break; case GSM_FCS: /* FCS follows the packet */ - gsm->received_fcs = c; - gsm_queue(gsm); + gsm->fcs = gsm_fcs_add(gsm->fcs, c); gsm->state = GSM_SSOF; break; case GSM_SSOF: - if (c == GSM0_SOF) { - gsm->state = GSM_SEARCH; - break; - } + gsm->state = GSM_SEARCH; + if (c == GSM0_SOF) + gsm_queue(gsm); + else + gsm->bad_size++; break; default: pr_debug("%s: unhandled state: %d\n", __func__, gsm->state); @@ -1989,11 +2275,24 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) return; } if (c == GSM1_SOF) { - /* 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 && gsm->count) { - /* Extract the FCS */ + /* EOF is only valid in frame if we have got to the data state */ + if (gsm->state == GSM_DATA) { + if (gsm->count < 1) { + /* Missing FSC */ + gsm->malformed++; + gsm->state = GSM_START; + return; + } + /* Remove the FCS from data */ 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->len = gsm->count; gsm_queue(gsm); @@ -2103,9 +2402,14 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) } /* Finish outstanding timers, making sure they are done */ + del_timer_sync(&gsm->kick_timer); del_timer_sync(&gsm->t2_timer); /* Free up any link layer users and finally the control channel */ + if (gsm->has_devices) { + gsm_unregister_devices(gsm_tty_driver, gsm->num); + gsm->has_devices = false; + } for (i = NUM_DLCI - 1; i >= 0; i--) if (gsm->dlci[i]) gsm_dlci_release(gsm->dlci[i]); @@ -2129,7 +2433,13 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) static int gsm_activate_mux(struct gsm_mux *gsm) { struct gsm_dlci *dlci; + int ret; + + dlci = gsm_dlci_alloc(gsm, 0); + if (dlci == NULL) + return -ENOMEM; + timer_setup(&gsm->kick_timer, gsm_kick_timer, 0); timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); init_waitqueue_head(&gsm->event); spin_lock_init(&gsm->control_lock); @@ -2140,9 +2450,11 @@ static int gsm_activate_mux(struct gsm_mux *gsm) else gsm->receive = gsm1_receive; - dlci = gsm_dlci_alloc(gsm, 0); - if (dlci == NULL) - return -ENOMEM; + ret = gsm_register_devices(gsm_tty_driver, gsm->num); + if (ret) + return ret; + + gsm->has_devices = true; gsm->dead = false; /* Tty opens are now permissible */ return 0; } @@ -2402,39 +2714,14 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len) * will need moving to an ioctl path. */ -static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) +static void gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) { - unsigned int base; - int ret, i; - 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); - if (ret != 0) - tty_kref_put(gsm->tty); - else { - /* Don't register device 0 - this is the control channel and not - a usable tty interface */ - base = mux_num_to_base(gsm); /* Base for this MUX */ - for (i = 1; i < NUM_DLCI; i++) { - struct device *dev; - - dev = tty_register_device(gsm_tty_driver, - base + i, NULL); - if (IS_ERR(dev)) { - for (i--; i >= 1; i--) - tty_unregister_device(gsm_tty_driver, - base + i); - return PTR_ERR(dev); - } - } - } - return ret; } - /** * gsmld_detach_gsm - stop doing 0710 mux * @tty: tty attached to the mux @@ -2445,12 +2732,7 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) { - unsigned int base = mux_num_to_base(gsm); /* Base for this MUX */ - int i; - WARN_ON(tty != gsm->tty); - for (i = 1; i < NUM_DLCI; i++) - tty_unregister_device(gsm_tty_driver, base + i); /* Restore tty XON/XOFF handling. */ gsm->tty->termios.c_iflag = gsm->old_c_iflag; tty_kref_put(gsm->tty); @@ -2471,7 +2753,8 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, flags = *fp++; switch (flags) { case TTY_NORMAL: - gsm->receive(gsm, *cp); + if (gsm->receive) + gsm->receive(gsm, *cp); break; case TTY_OVERRUN: case TTY_BREAK: @@ -2542,7 +2825,6 @@ static void gsmld_close(struct tty_struct *tty) static int gsmld_open(struct tty_struct *tty) { struct gsm_mux *gsm; - int ret; if (tty->ops->write == NULL) return -EINVAL; @@ -2558,12 +2840,12 @@ static int gsmld_open(struct tty_struct *tty) /* Attach the initial passive connection */ gsm->encoding = 1; - ret = gsmld_attach_gsm(tty, gsm); - if (ret != 0) { - gsm_cleanup_mux(gsm, false); - mux_put(gsm); - } - return ret; + gsmld_attach_gsm(tty, gsm); + + timer_setup(&gsm->kick_timer, gsm_kick_timer, 0); + timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); + + return 0; } /** @@ -2631,11 +2913,24 @@ static ssize_t gsmld_read(struct tty_struct *tty, struct file *file, static ssize_t gsmld_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr) { - int space = tty_write_room(tty); + struct gsm_mux *gsm = tty->disc_data; + unsigned long flags; + int space; + int ret; + + if (!gsm) + return -ENODEV; + + ret = -ENOBUFS; + spin_lock_irqsave(&gsm->tx_lock, flags); + space = tty_write_room(tty); if (space >= nr) - return tty->ops->write(tty, buf, nr); - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - return -ENOBUFS; + ret = tty->ops->write(tty, buf, nr); + else + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + spin_unlock_irqrestore(&gsm->tx_lock, flags); + + return ret; } /** @@ -2660,12 +2955,15 @@ static __poll_t gsmld_poll(struct tty_struct *tty, struct file *file, poll_wait(file, &tty->read_wait, wait); poll_wait(file, &tty->write_wait, wait); + + if (gsm->dead) + mask |= EPOLLHUP; if (tty_hung_up_p(file)) mask |= EPOLLHUP; + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + mask |= EPOLLHUP; if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0) mask |= EPOLLOUT | EPOLLWRNORM; - if (gsm->dead) - mask |= EPOLLHUP; return mask; } @@ -2915,14 +3213,43 @@ static struct tty_ldisc_ops tty_ldisc_packet = { * Virtual tty side */ -#define TX_SIZE 512 +/** + * 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) +{ + 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 gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk) +static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk) { u8 modembits[3]; struct gsm_control *ctrl; int len = 2; + if (dlci->gsm->encoding != 0) + return 0; + modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */ if (!brk) { modembits[1] = (gsm_encode_modem(dlci) << 1) | EA; @@ -2937,6 +3264,27 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk) 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) { struct gsm_dlci *dlci = container_of(port, struct gsm_dlci, port); @@ -2969,7 +3317,7 @@ static void gsm_dtr_rts(struct tty_port *port, int onoff) modem_tx &= ~(TIOCM_DTR | TIOCM_RTS); if (modem_tx != dlci->modem_tx) { dlci->modem_tx = modem_tx; - gsmtty_modem_update(dlci, 0); + gsm_modem_update(dlci, 0); } } @@ -3039,6 +3387,7 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) { struct gsm_dlci *dlci = tty->driver_data; struct tty_port *port = &dlci->port; + struct gsm_mux *gsm = dlci->gsm; port->count++; tty_port_tty_set(port, tty); @@ -3048,7 +3397,10 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp) a DM straight back. This is ok as that will have caused a hangup */ tty_port_set_initialized(port, 1); /* Start sending off SABM messages */ - gsm_dlci_begin_open(dlci); + if (gsm->initiator) + gsm_dlci_begin_open(dlci); + else + gsm_dlci_set_opening(dlci); /* And wait for virtual carrier */ return tty_port_block_til_ready(port, tty, filp); } @@ -3102,7 +3454,7 @@ static unsigned int gsmtty_write_room(struct tty_struct *tty) struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) return 0; - return TX_SIZE - kfifo_len(&dlci->fifo); + return kfifo_avail(&dlci->fifo); } static unsigned int gsmtty_chars_in_buffer(struct tty_struct *tty) @@ -3158,7 +3510,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty, if (modem_tx != dlci->modem_tx) { dlci->modem_tx = modem_tx; - return gsmtty_modem_update(dlci, 0); + return gsm_modem_update(dlci, 0); } return 0; } @@ -3219,7 +3571,7 @@ static void gsmtty_throttle(struct tty_struct *tty) dlci->modem_tx &= ~TIOCM_RTS; dlci->throttled = true; /* Send an MSC with RTS cleared */ - gsmtty_modem_update(dlci, 0); + gsm_modem_update(dlci, 0); } static void gsmtty_unthrottle(struct tty_struct *tty) @@ -3231,7 +3583,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty) dlci->modem_tx |= TIOCM_RTS; dlci->throttled = false; /* 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) @@ -3249,7 +3601,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state) if (encode > 0x0F) encode = 0x0F; /* Best effort */ } - return gsmtty_modem_update(dlci, encode); + return gsm_modem_update(dlci, encode); } static void gsmtty_cleanup(struct tty_struct *tty) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 74bfabe5b453..752dab3356d7 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -111,21 +111,11 @@ static void pty_unthrottle(struct tty_struct *tty) static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) { struct tty_struct *to = tty->link; - unsigned long flags; - if (tty->flow.stopped) + if (tty->flow.stopped || !c) return 0; - if (c > 0) { - spin_lock_irqsave(&to->port->lock, flags); - /* Stuff the data into the input queue of the other end */ - c = tty_insert_flip_string(to->port, buf, c); - spin_unlock_irqrestore(&to->port->lock, flags); - /* And shovel */ - if (c) - tty_flip_buffer_push(to->port); - } - return c; + return tty_insert_flip_string_and_push_buffer(to->port, buf, c); } /** diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 6473361525d1..b3abc29aa927 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -17,6 +17,8 @@ struct uart_8250_dma { int (*tx_dma)(struct uart_8250_port *p); int (*rx_dma)(struct uart_8250_port *p); + void (*prepare_tx_dma)(struct uart_8250_port *p); + void (*prepare_rx_dma)(struct uart_8250_port *p); /* Filter function */ dma_filter_fn fn; @@ -120,6 +122,28 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value) up->port.serial_out(&up->port, offset, value); } +/* + * For the 16C950 + */ +static void serial_icr_write(struct uart_8250_port *up, int offset, int value) +{ + serial_out(up, UART_SCR, offset); + serial_out(up, UART_ICR, value); +} + +static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up, + int offset) +{ + unsigned int value; + + serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); + serial_out(up, UART_SCR, offset); + value = serial_in(up, UART_ICR); + serial_icr_write(up, UART_ACR, up->acr); + + return value; +} + void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p); static inline int serial_dl_read(struct uart_8250_port *up) @@ -309,6 +333,22 @@ extern int serial8250_rx_dma(struct uart_8250_port *); extern void serial8250_rx_dma_flush(struct uart_8250_port *); extern int serial8250_request_dma(struct uart_8250_port *); extern void serial8250_release_dma(struct uart_8250_port *); + +static inline void serial8250_do_prepare_tx_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + + if (dma->prepare_tx_dma) + dma->prepare_tx_dma(p); +} + +static inline void serial8250_do_prepare_rx_dma(struct uart_8250_port *p) +{ + struct uart_8250_dma *dma = p->dma; + + if (dma->prepare_rx_dma) + dma->prepare_rx_dma(p); +} #else static inline int serial8250_tx_dma(struct uart_8250_port *p) { diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 0877cf24f7de..711cf30e835a 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -1141,16 +1141,19 @@ static int __maybe_unused brcmuart_suspend(struct device *dev) struct brcmuart_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up = serial8250_get_port(priv->line); struct uart_port *port = &up->port; - - serial8250_suspend_port(priv->line); - clk_disable_unprepare(priv->baud_mux_clk); + unsigned long flags; /* * This will prevent resume from enabling RTS before the - * baud rate has been resored. + * baud rate has been restored. */ + spin_lock_irqsave(&port->lock, flags); priv->saved_mctrl = port->mctrl; - port->mctrl = 0; + port->mctrl &= ~TIOCM_RTS; + spin_unlock_irqrestore(&port->lock, flags); + + serial8250_suspend_port(priv->line); + clk_disable_unprepare(priv->baud_mux_clk); return 0; } @@ -1160,6 +1163,7 @@ static int __maybe_unused brcmuart_resume(struct device *dev) struct brcmuart_priv *priv = dev_get_drvdata(dev); struct uart_8250_port *up = serial8250_get_port(priv->line); struct uart_port *port = &up->port; + unsigned long flags; int ret; ret = clk_prepare_enable(priv->baud_mux_clk); @@ -1182,7 +1186,15 @@ static int __maybe_unused brcmuart_resume(struct device *dev) start_rx_dma(serial8250_get_port(priv->line)); } serial8250_resume_port(priv->line); - port->mctrl = priv->saved_mctrl; + + if (priv->saved_mctrl & TIOCM_RTS) { + /* Restore RTS */ + spin_lock_irqsave(&port->lock, flags); + port->mctrl |= TIOCM_RTS; + port->ops->set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); + } + return 0; } diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 1ce193daea7f..30b7890645ac 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -23,6 +23,7 @@ #include <linux/sysrq.h> #include <linux/delay.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/tty.h> #include <linux/ratelimit.h> #include <linux/tty_flip.h> @@ -561,6 +562,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) up->port.dev = dev; + if (uart_console_enabled(&up->port)) + pm_runtime_get_sync(up->port.dev); + serial8250_apply_quirks(up); uart_add_one_port(drv, &up->port); } diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c index b3c3f7e5851a..1bdc8d6432fe 100644 --- a/drivers/tty/serial/8250/8250_dma.c +++ b/drivers/tty/serial/8250/8250_dma.c @@ -86,6 +86,8 @@ int serial8250_tx_dma(struct uart_8250_port *p) dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + serial8250_do_prepare_tx_dma(p); + desc = dmaengine_prep_slave_single(dma->txchan, dma->tx_addr + xmit->tail, dma->tx_size, DMA_MEM_TO_DEV, @@ -123,6 +125,8 @@ int serial8250_rx_dma(struct uart_8250_port *p) if (dma->rx_running) return 0; + serial8250_do_prepare_rx_dma(p); + desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 49559731bbcf..ace221afeb03 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -124,12 +124,15 @@ static void dw8250_check_lcr(struct uart_port *p, int value) /* Returns once the transmitter is empty or we run out of retries */ static void dw8250_tx_wait_empty(struct uart_port *p) { + struct uart_8250_port *up = up_to_u8250p(p); unsigned int tries = 20000; unsigned int delay_threshold = tries - 1000; unsigned int lsr; while (tries--) { lsr = readb (p->membase + (UART_LSR << p->regshift)); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + if (lsr & UART_LSR_TEMT) break; diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index fc65a2293ce9..af74f82ad782 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -81,7 +81,7 @@ int fsl8250_handle_irq(struct uart_port *port) if ((lsr & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) serial8250_tx_chars(up); - up->lsr_saved_flags = orig_lsr; + up->lsr_saved_flags |= orig_lsr & UART_LSR_BI; uart_unlock_and_check_sysrq_irqrestore(&up->port, flags); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e7b9805903f4..a16743856fc7 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -11,6 +11,7 @@ #include <linux/pci.h> #include <linux/string.h> #include <linux/kernel.h> +#include <linux/math.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/tty.h> @@ -75,13 +76,12 @@ static int pci_default_setup(struct serial_private*, static void moan_device(const char *str, struct pci_dev *dev) { - dev_err(&dev->dev, - "%s: %s\n" + pci_err(dev, "%s\n" "Please send the output of lspci -vv, this\n" "message (0x%04x,0x%04x,0x%04x,0x%04x), the\n" "manufacturer and name of serial board or\n" "modem board to <linux-serial@vger.kernel.org>.\n", - pci_name(dev), str, dev->vendor, dev->device, + str, dev->vendor, dev->device, dev->subsystem_vendor, dev->subsystem_device); } @@ -238,7 +238,7 @@ static int pci_inteli960ni_init(struct pci_dev *dev) /* is firmware started? */ pci_read_config_dword(dev, 0x44, &oldval); if (oldval == 0x00001000L) { /* RESET value */ - dev_dbg(&dev->dev, "Local i960 firmware missing\n"); + pci_dbg(dev, "Local i960 firmware missing\n"); return -ENODEV; } return 0; @@ -588,9 +588,8 @@ static int pci_timedia_probe(struct pci_dev *dev) * (0,2,3,5,6: serial only -- 7,8,9: serial + parallel) */ if ((dev->subsystem_device & 0x00f0) >= 0x70) { - dev_info(&dev->dev, - "ignoring Timedia subdevice %04x for parport_serial\n", - dev->subsystem_device); + pci_info(dev, "ignoring Timedia subdevice %04x for parport_serial\n", + dev->subsystem_device); return -ENODEV; } @@ -827,8 +826,7 @@ static int pci_netmos_9900_numports(struct pci_dev *dev) if (sub_serports > 0) return sub_serports; - dev_err(&dev->dev, - "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); + pci_err(dev, "NetMos/Mostech serial driver ignoring port on ambiguous config.\n"); return 0; } @@ -897,18 +895,16 @@ static int pci_netmos_init(struct pci_dev *dev) /* enable IO_Space bit */ #define ITE_887x_POSIO_ENABLE (1 << 31) +/* inta_addr are the configuration addresses of the ITE */ +static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, 0x200, 0x280 }; static int pci_ite887x_init(struct pci_dev *dev) { - /* inta_addr are the configuration addresses of the ITE */ - static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0, - 0x200, 0x280, 0 }; int ret, i, type; struct resource *iobase = NULL; u32 miscr, uartbar, ioport; /* search for the base-ioport */ - i = 0; - while (inta_addr[i] && iobase == NULL) { + for (i = 0; i < ARRAY_SIZE(inta_addr); i++) { iobase = request_region(inta_addr[i], ITE_887x_IOSIZE, "ite887x"); if (iobase != NULL) { @@ -925,13 +921,11 @@ static int pci_ite887x_init(struct pci_dev *dev) break; } release_region(iobase->start, ITE_887x_IOSIZE); - iobase = NULL; } - i++; } - if (!inta_addr[i]) { - dev_err(&dev->dev, "ite887x: could not find iobase\n"); + if (i == ARRAY_SIZE(inta_addr)) { + pci_err(dev, "could not find iobase\n"); return -ENODEV; } @@ -1001,43 +995,29 @@ static void pci_ite887x_exit(struct pci_dev *dev) } /* - * EndRun Technologies. - * Determine the number of ports available on the device. + * Oxford Semiconductor Inc. + * Check if an OxSemi device is part of the Tornado range of devices. */ #define PCI_VENDOR_ID_ENDRUN 0x7401 #define PCI_DEVICE_ID_ENDRUN_1588 0xe100 -static int pci_endrun_init(struct pci_dev *dev) +static bool pci_oxsemi_tornado_p(struct pci_dev *dev) { - u8 __iomem *p; - unsigned long deviceID; - unsigned int number_uarts = 0; + /* OxSemi Tornado devices are all 0xCxxx */ + if (dev->vendor == PCI_VENDOR_ID_OXSEMI && + (dev->device & 0xf000) != 0xc000) + return false; - /* EndRun device is all 0xexxx */ + /* EndRun devices are all 0xExxx */ if (dev->vendor == PCI_VENDOR_ID_ENDRUN && - (dev->device & 0xf000) != 0xe000) - return 0; - - p = pci_iomap(dev, 0, 5); - if (p == NULL) - return -ENOMEM; + (dev->device & 0xf000) != 0xe000) + return false; - deviceID = ioread32(p); - /* EndRun device */ - if (deviceID == 0x07000200) { - number_uarts = ioread8(p + 4); - dev_dbg(&dev->dev, - "%d ports detected on EndRun PCI Express device\n", - number_uarts); - } - pci_iounmap(dev, p); - return number_uarts; + return true; } /* - * Oxford Semiconductor Inc. - * Check that device is part of the Tornado range of devices, then determine - * the number of ports available on the device. + * Determine the number of ports available on a Tornado device. */ static int pci_oxsemi_tornado_init(struct pci_dev *dev) { @@ -1045,9 +1025,7 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) unsigned long deviceID; unsigned int number_uarts = 0; - /* OxSemi Tornado devices are all 0xCxxx */ - if (dev->vendor == PCI_VENDOR_ID_OXSEMI && - (dev->device & 0xF000) != 0xC000) + if (!pci_oxsemi_tornado_p(dev)) return 0; p = pci_iomap(dev, 0, 5); @@ -1058,14 +1036,217 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev) /* Tornado device */ if (deviceID == 0x07000200) { number_uarts = ioread8(p + 4); - dev_dbg(&dev->dev, - "%d ports detected on Oxford PCI Express device\n", - number_uarts); + pci_dbg(dev, "%d ports detected on %s PCI Express device\n", + number_uarts, + dev->vendor == PCI_VENDOR_ID_ENDRUN ? + "EndRun" : "Oxford"); } pci_iounmap(dev, p); return number_uarts; } +/* Tornado-specific constants for the TCR and CPR registers; see below. */ +#define OXSEMI_TORNADO_TCR_MASK 0xf +#define OXSEMI_TORNADO_CPR_MASK 0x1ff +#define OXSEMI_TORNADO_CPR_MIN 0x008 +#define OXSEMI_TORNADO_CPR_DEF 0x10f + +/* + * Determine the oversampling rate, the clock prescaler, and the clock + * divisor for the requested baud rate. The clock rate is 62.5 MHz, + * which is four times the baud base, and the prescaler increments in + * steps of 1/8. Therefore to make calculations on integers we need + * to use a scaled clock rate, which is the baud base multiplied by 32 + * (or our assumed UART clock rate multiplied by 2). + * + * The allowed oversampling rates are from 4 up to 16 inclusive (values + * from 0 to 3 inclusive map to 16). Likewise the clock prescaler allows + * values between 1.000 and 63.875 inclusive (operation for values from + * 0.000 to 0.875 has not been specified). The clock divisor is the usual + * unsigned 16-bit integer. + * + * For the most accurate baud rate we use a table of predetermined + * oversampling rates and clock prescalers that records all possible + * products of the two parameters in the range from 4 up to 255 inclusive, + * and additionally 335 for the 1500000bps rate, with the prescaler scaled + * by 8. The table is sorted by the decreasing value of the oversampling + * rate and ties are resolved by sorting by the decreasing value of the + * product. This way preference is given to higher oversampling rates. + * + * We iterate over the table and choose the product of an oversampling + * rate and a clock prescaler that gives the lowest integer division + * result deviation, or if an exact integer divider is found we stop + * looking for it right away. We do some fixup if the resulting clock + * divisor required would be out of its unsigned 16-bit integer range. + * + * Finally we abuse the supposed fractional part returned to encode the + * 4-bit value of the oversampling rate and the 9-bit value of the clock + * prescaler which will end up in the TCR and CPR/CPR2 registers. + */ +static unsigned int pci_oxsemi_tornado_get_divisor(struct uart_port *port, + unsigned int baud, + unsigned int *frac) +{ + static u8 p[][2] = { + { 16, 14, }, { 16, 13, }, { 16, 12, }, { 16, 11, }, + { 16, 10, }, { 16, 9, }, { 16, 8, }, { 15, 17, }, + { 15, 16, }, { 15, 15, }, { 15, 14, }, { 15, 13, }, + { 15, 12, }, { 15, 11, }, { 15, 10, }, { 15, 9, }, + { 15, 8, }, { 14, 18, }, { 14, 17, }, { 14, 14, }, + { 14, 13, }, { 14, 12, }, { 14, 11, }, { 14, 10, }, + { 14, 9, }, { 14, 8, }, { 13, 19, }, { 13, 18, }, + { 13, 17, }, { 13, 13, }, { 13, 12, }, { 13, 11, }, + { 13, 10, }, { 13, 9, }, { 13, 8, }, { 12, 19, }, + { 12, 18, }, { 12, 17, }, { 12, 11, }, { 12, 9, }, + { 12, 8, }, { 11, 23, }, { 11, 22, }, { 11, 21, }, + { 11, 20, }, { 11, 19, }, { 11, 18, }, { 11, 17, }, + { 11, 11, }, { 11, 10, }, { 11, 9, }, { 11, 8, }, + { 10, 25, }, { 10, 23, }, { 10, 20, }, { 10, 19, }, + { 10, 17, }, { 10, 10, }, { 10, 9, }, { 10, 8, }, + { 9, 27, }, { 9, 23, }, { 9, 21, }, { 9, 19, }, + { 9, 18, }, { 9, 17, }, { 9, 9, }, { 9, 8, }, + { 8, 31, }, { 8, 29, }, { 8, 23, }, { 8, 19, }, + { 8, 17, }, { 8, 8, }, { 7, 35, }, { 7, 31, }, + { 7, 29, }, { 7, 25, }, { 7, 23, }, { 7, 21, }, + { 7, 19, }, { 7, 17, }, { 7, 15, }, { 7, 14, }, + { 7, 13, }, { 7, 12, }, { 7, 11, }, { 7, 10, }, + { 7, 9, }, { 7, 8, }, { 6, 41, }, { 6, 37, }, + { 6, 31, }, { 6, 29, }, { 6, 23, }, { 6, 19, }, + { 6, 17, }, { 6, 13, }, { 6, 11, }, { 6, 10, }, + { 6, 9, }, { 6, 8, }, { 5, 67, }, { 5, 47, }, + { 5, 43, }, { 5, 41, }, { 5, 37, }, { 5, 31, }, + { 5, 29, }, { 5, 25, }, { 5, 23, }, { 5, 19, }, + { 5, 17, }, { 5, 15, }, { 5, 13, }, { 5, 11, }, + { 5, 10, }, { 5, 9, }, { 5, 8, }, { 4, 61, }, + { 4, 59, }, { 4, 53, }, { 4, 47, }, { 4, 43, }, + { 4, 41, }, { 4, 37, }, { 4, 31, }, { 4, 29, }, + { 4, 23, }, { 4, 19, }, { 4, 17, }, { 4, 13, }, + { 4, 9, }, { 4, 8, }, + }; + /* Scale the quotient for comparison to get the fractional part. */ + const unsigned int quot_scale = 65536; + unsigned int sclk = port->uartclk * 2; + unsigned int sdiv = DIV_ROUND_CLOSEST(sclk, baud); + unsigned int best_squot; + unsigned int squot; + unsigned int quot; + u16 cpr; + u8 tcr; + int i; + + /* Old custom speed handling. */ + if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) { + unsigned int cust_div = port->custom_divisor; + + quot = cust_div & UART_DIV_MAX; + tcr = (cust_div >> 16) & OXSEMI_TORNADO_TCR_MASK; + cpr = (cust_div >> 20) & OXSEMI_TORNADO_CPR_MASK; + if (cpr < OXSEMI_TORNADO_CPR_MIN) + cpr = OXSEMI_TORNADO_CPR_DEF; + } else { + best_squot = quot_scale; + for (i = 0; i < ARRAY_SIZE(p); i++) { + unsigned int spre; + unsigned int srem; + u8 cp; + u8 tc; + + tc = p[i][0]; + cp = p[i][1]; + spre = tc * cp; + + srem = sdiv % spre; + if (srem > spre / 2) + srem = spre - srem; + squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre); + + if (srem == 0) { + tcr = tc; + cpr = cp; + quot = sdiv / spre; + break; + } else if (squot < best_squot) { + best_squot = squot; + tcr = tc; + cpr = cp; + quot = DIV_ROUND_CLOSEST(sdiv, spre); + } + } + while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 && + quot % 2 == 0) { + quot >>= 1; + tcr <<= 1; + } + while (quot > UART_DIV_MAX) { + if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) { + quot >>= 1; + tcr <<= 1; + } else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) { + quot >>= 1; + cpr <<= 1; + } else { + quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK; + cpr = OXSEMI_TORNADO_CPR_MASK; + } + } + } + + *frac = (cpr << 8) | (tcr & OXSEMI_TORNADO_TCR_MASK); + return quot; +} + +/* + * Set the oversampling rate in the transmitter clock cycle register (TCR), + * the clock prescaler in the clock prescaler register (CPR and CPR2), and + * the clock divisor in the divisor latch (DLL and DLM). Note that for + * backwards compatibility any write to CPR clears CPR2 and therefore CPR + * has to be written first, followed by CPR2, which occupies the location + * of CKS used with earlier UART designs. + */ +static void pci_oxsemi_tornado_set_divisor(struct uart_port *port, + unsigned int baud, + unsigned int quot, + unsigned int quot_frac) +{ + struct uart_8250_port *up = up_to_u8250p(port); + u8 cpr2 = quot_frac >> 16; + u8 cpr = quot_frac >> 8; + u8 tcr = quot_frac; + + serial_icr_write(up, UART_TCR, tcr); + serial_icr_write(up, UART_CPR, cpr); + serial_icr_write(up, UART_CKS, cpr2); + serial8250_do_set_divisor(port, baud, quot, 0); +} + +/* + * For Tornado devices we force MCR[7] set for the Divide-by-M N/8 baud rate + * generator prescaler (CPR and CPR2). Otherwise no prescaler would be used. + */ +static void pci_oxsemi_tornado_set_mctrl(struct uart_port *port, + unsigned int mctrl) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + up->mcr |= UART_MCR_CLKSEL; + serial8250_do_set_mctrl(port, mctrl); +} + +static int pci_oxsemi_tornado_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *up, int idx) +{ + struct pci_dev *dev = priv->dev; + + if (pci_oxsemi_tornado_p(dev)) { + up->port.get_divisor = pci_oxsemi_tornado_get_divisor; + up->port.set_divisor = pci_oxsemi_tornado_set_divisor; + up->port.set_mctrl = pci_oxsemi_tornado_set_mctrl; + } + + return pci_default_setup(priv, board, up, idx); +} + static int pci_asix_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) @@ -1120,15 +1301,15 @@ static struct quatech_feature quatech_cards[] = { { 0, } }; -static int pci_quatech_amcc(u16 devid) +static int pci_quatech_amcc(struct pci_dev *dev) { struct quatech_feature *qf = &quatech_cards[0]; while (qf->devid) { - if (qf->devid == devid) + if (qf->devid == dev->device) return qf->amcc; qf++; } - pr_err("quatech: unknown port type '0x%04X'.\n", devid); + pci_err(dev, "unknown port type '0x%04X'.\n", dev->device); return 0; }; @@ -1291,7 +1472,7 @@ static int pci_quatech_rs422(struct uart_8250_port *port) static int pci_quatech_init(struct pci_dev *dev) { - if (pci_quatech_amcc(dev->device)) { + if (pci_quatech_amcc(dev)) { unsigned long base = pci_resource_start(dev, 0); if (base) { u32 tmp; @@ -1315,7 +1496,7 @@ static int pci_quatech_setup(struct serial_private *priv, port->port.uartclk = pci_quatech_clock(port); /* For now just warn about RS422 */ if (pci_quatech_rs422(port)) - pr_warn("quatech: software control of RS422 features not currently supported.\n"); + pci_warn(priv->dev, "software control of RS422 features not currently supported.\n"); return pci_default_setup(priv, board, port, idx); } @@ -1529,7 +1710,7 @@ static int pci_fintek_setup(struct serial_private *priv, /* Get the io address from configuration space */ pci_read_config_word(pdev, config_base + 4, &iobase); - dev_dbg(&pdev->dev, "%s: idx=%d iobase=0x%x", __func__, idx, iobase); + pci_dbg(pdev, "idx=%d iobase=0x%x", idx, iobase); port->port.iotype = UPIO_PORT; port->port.iobase = iobase; @@ -1693,7 +1874,7 @@ static int skip_tx_en_setup(struct serial_private *priv, struct uart_8250_port *port, int idx) { port->port.quirks |= UPQ_NO_TXEN_TEST; - dev_dbg(&priv->dev->dev, + pci_dbg(priv->dev, "serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n", priv->dev->vendor, priv->dev->device, priv->dev->subsystem_vendor, priv->dev->subsystem_device); @@ -2517,7 +2698,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .init = pci_endrun_init, + .init = pci_oxsemi_tornado_init, .setup = pci_default_setup, }, /* @@ -2529,7 +2710,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_oxsemi_tornado_init, - .setup = pci_default_setup, + .setup = pci_oxsemi_tornado_setup, }, { .vendor = PCI_VENDOR_ID_MAINPINE, @@ -2537,7 +2718,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .init = pci_oxsemi_tornado_init, - .setup = pci_default_setup, + .setup = pci_oxsemi_tornado_setup, }, { .vendor = PCI_VENDOR_ID_DIGI, @@ -2545,7 +2726,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .subvendor = PCI_SUBVENDOR_ID_IBM, .subdevice = PCI_ANY_ID, .init = pci_oxsemi_tornado_init, - .setup = pci_default_setup, + .setup = pci_oxsemi_tornado_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, @@ -2862,7 +3043,7 @@ enum pci_board_num_t { pbn_b0_2_1843200, pbn_b0_4_1843200, - pbn_b0_1_3906250, + pbn_b0_1_15625000, pbn_b0_bt_1_115200, pbn_b0_bt_2_115200, @@ -2940,12 +3121,11 @@ enum pci_board_num_t { pbn_panacom2, pbn_panacom4, pbn_plx_romulus, - pbn_endrun_2_3906250, pbn_oxsemi, - pbn_oxsemi_1_3906250, - pbn_oxsemi_2_3906250, - pbn_oxsemi_4_3906250, - pbn_oxsemi_8_3906250, + pbn_oxsemi_1_15625000, + pbn_oxsemi_2_15625000, + pbn_oxsemi_4_15625000, + pbn_oxsemi_8_15625000, pbn_intel_i960, pbn_sgi_ioc3, pbn_computone_4, @@ -3092,10 +3272,10 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 8, }, - [pbn_b0_1_3906250] = { + [pbn_b0_1_15625000] = { .flags = FL_BASE0, .num_ports = 1, - .base_baud = 3906250, + .base_baud = 15625000, .uart_offset = 8, }, @@ -3467,20 +3647,6 @@ static struct pciserial_board pci_boards[] = { }, /* - * EndRun Technologies - * Uses the size of PCI Base region 0 to - * signal now many ports are available - * 2 port 952 Uart support - */ - [pbn_endrun_2_3906250] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 3906250, - .uart_offset = 0x200, - .first_offset = 0x1000, - }, - - /* * This board uses the size of PCI Base region 0 to * signal now many ports are available */ @@ -3490,31 +3656,31 @@ static struct pciserial_board pci_boards[] = { .base_baud = 115200, .uart_offset = 8, }, - [pbn_oxsemi_1_3906250] = { + [pbn_oxsemi_1_15625000] = { .flags = FL_BASE0, .num_ports = 1, - .base_baud = 3906250, + .base_baud = 15625000, .uart_offset = 0x200, .first_offset = 0x1000, }, - [pbn_oxsemi_2_3906250] = { + [pbn_oxsemi_2_15625000] = { .flags = FL_BASE0, .num_ports = 2, - .base_baud = 3906250, + .base_baud = 15625000, .uart_offset = 0x200, .first_offset = 0x1000, }, - [pbn_oxsemi_4_3906250] = { + [pbn_oxsemi_4_15625000] = { .flags = FL_BASE0, .num_ports = 4, - .base_baud = 3906250, + .base_baud = 15625000, .uart_offset = 0x200, .first_offset = 0x1000, }, - [pbn_oxsemi_8_3906250] = { + [pbn_oxsemi_8_15625000] = { .flags = FL_BASE0, .num_ports = 8, - .base_baud = 3906250, + .base_baud = 15625000, .uart_offset = 0x200, .first_offset = 0x1000, }, @@ -4011,12 +4177,12 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) uart.port.irq = 0; } else { if (pci_match_id(pci_use_msi, dev)) { - dev_dbg(&dev->dev, "Using MSI(-X) interrupts\n"); + pci_dbg(dev, "Using MSI(-X) interrupts\n"); pci_set_master(dev); uart.port.flags &= ~UPF_SHARE_IRQ; rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); } else { - dev_dbg(&dev->dev, "Using legacy interrupts\n"); + pci_dbg(dev, "Using legacy interrupts\n"); rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY); } if (rc < 0) { @@ -4034,12 +4200,12 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board) if (quirk->setup(priv, board, &uart, i)) break; - dev_dbg(&dev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", + pci_dbg(dev, "Setup PCI port: port %lx, irq %d, type %d\n", uart.port.iobase, uart.port.irq, uart.port.iotype); priv->line[i] = serial8250_register_8250_port(&uart); if (priv->line[i] < 0) { - dev_err(&dev->dev, + pci_err(dev, "Couldn't register serial port %lx, irq %d, type %d, error %d\n", uart.port.iobase, uart.port.irq, uart.port.iotype, priv->line[i]); @@ -4135,8 +4301,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) } if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { - dev_err(&dev->dev, "invalid driver_data: %ld\n", - ent->driver_data); + pci_err(dev, "invalid driver_data: %ld\n", ent->driver_data); return -EINVAL; } @@ -4219,7 +4384,7 @@ static int pciserial_resume_one(struct device *dev) err = pci_enable_device(pdev); /* FIXME: We cannot simply error out here */ if (err) - dev_err(dev, "Unable to re-enable ports, trying to continue.\n"); + pci_err(pdev, "Unable to re-enable ports, trying to continue.\n"); pciserial_resume_ports(priv); } return 0; @@ -4413,13 +4578,6 @@ static const struct pci_device_id serial_pci_tbl[] = { 0x10b5, 0x106a, 0, 0, pbn_plx_romulus }, /* - * EndRun Technologies. PCI express device range. - * EndRun PTP/1588 has 2 Native UARTs. - */ - { PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_endrun_2_3906250 }, - /* * Quatech cards. These actually have configurable clocks but for * now we just use the default. * @@ -4528,158 +4686,165 @@ static const struct pci_device_id serial_pci_tbl[] = { */ { PCI_VENDOR_ID_OXSEMI, 0xc101, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_3906250 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc105, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_3906250 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc11b, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc11f, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc120, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_3906250 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc124, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_3906250 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc138, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc13d, /* OXPCIe952 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc140, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_3906250 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc141, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_3906250 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc144, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_3906250 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc145, /* OXPCIe952 1 Legacy UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_3906250 }, + pbn_b0_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc158, /* OXPCIe952 2 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_3906250 }, + pbn_oxsemi_2_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc15d, /* OXPCIe952 2 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_3906250 }, + pbn_oxsemi_2_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc208, /* OXPCIe954 4 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_3906250 }, + pbn_oxsemi_4_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc20d, /* OXPCIe954 4 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_4_3906250 }, + pbn_oxsemi_4_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc308, /* OXPCIe958 8 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_3906250 }, + pbn_oxsemi_8_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc30d, /* OXPCIe958 8 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_8_3906250 }, + pbn_oxsemi_8_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc40b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc40f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc41b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc41f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc42b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc42f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc43b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc43f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc44b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc44f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc45b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc45f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc46b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc46f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc47b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc47f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc48b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc48f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc49b, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc49f, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4ab, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4af, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4bb, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4bf, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4cb, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_OXSEMI, 0xc4cf, /* OXPCIe200 1 Native UART */ PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, /* * Mainpine Inc. IQ Express "Rev3" utilizing OxSemi Tornado */ { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 1 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4001, 0, 0, - pbn_oxsemi_1_3906250 }, + pbn_oxsemi_1_15625000 }, { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 2 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4002, 0, 0, - pbn_oxsemi_2_3906250 }, + pbn_oxsemi_2_15625000 }, { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 4 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4004, 0, 0, - pbn_oxsemi_4_3906250 }, + pbn_oxsemi_4_15625000 }, { PCI_VENDOR_ID_MAINPINE, 0x4000, /* IQ Express 8 Port V.34 Super-G3 Fax */ PCI_VENDOR_ID_MAINPINE, 0x4008, 0, 0, - pbn_oxsemi_8_3906250 }, + pbn_oxsemi_8_15625000 }, /* * Digi/IBM PCIe 2-port Async EIA-232 Adapter utilizing OxSemi Tornado */ { PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_2_OX_IBM, PCI_SUBVENDOR_ID_IBM, PCI_ANY_ID, 0, 0, - pbn_oxsemi_2_3906250 }, + pbn_oxsemi_2_15625000 }, + /* + * EndRun Technologies. PCI express device range. + * EndRun PTP/1588 has 2 Native UARTs utilizing OxSemi 952. + */ + { PCI_VENDOR_ID_ENDRUN, PCI_DEVICE_ID_ENDRUN_1588, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_oxsemi_2_15625000 }, /* * SBS Technologies, Inc. P-Octal and PMC-OCTPRO cards, @@ -5311,6 +5476,115 @@ static const struct pci_device_id serial_pci_tbl[] = { 0, 0, pbn_b2_4_115200 }, /* + * Brainboxes PX-101 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4005, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4019, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-235/246 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4004, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_1_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4016, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes PX-203/PX-257 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4006, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_2_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4015, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-260/PX-701 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400A, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-310 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400E, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-313 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400C, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_2_15625000 }, + /* + * Brainboxes PX-320/324/PX-376/PX-387 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400B, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes PX-335/346 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x400F, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-368 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4010, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-420 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4000, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_4_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4011, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_4_15625000 }, + /* + * Brainboxes PX-803 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4009, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_1_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x401E, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + /* + * Brainboxes PX-846 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x4008, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_b0_1_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x4017, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + pbn_oxsemi_1_15625000 }, + + /* * Perle PCI-RAS cards */ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index df9731f73746..a5496bd1b650 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -538,27 +538,6 @@ serial_port_out_sync(struct uart_port *p, int offset, int value) } /* - * For the 16C950 - */ -static void serial_icr_write(struct uart_8250_port *up, int offset, int value) -{ - serial_out(up, UART_SCR, offset); - serial_out(up, UART_ICR, value); -} - -static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) -{ - unsigned int value; - - serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); - serial_out(up, UART_SCR, offset); - value = serial_in(up, UART_ICR); - serial_icr_write(up, UART_ACR, up->acr); - - return value; -} - -/* * FIFO support. */ static void serial8250_clear_fifos(struct uart_8250_port *p) @@ -2982,8 +2961,10 @@ static int serial8250_request_std_resource(struct uart_8250_port *up) case UPIO_MEM32BE: case UPIO_MEM16: case UPIO_MEM: - if (!port->mapbase) + if (!port->mapbase) { + ret = -EINVAL; break; + } if (!request_mem_region(port->mapbase, size, "serial")) { ret = -EBUSY; diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 0e908061b5d7..300a8bbb4b80 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1372,6 +1372,15 @@ static void pl011_stop_rx(struct uart_port *port) pl011_dma_rx_stop(uap); } +static void pl011_throttle_rx(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + pl011_stop_rx(port); + spin_unlock_irqrestore(&port->lock, flags); +} + static void pl011_enable_ms(struct uart_port *port) { struct uart_amba_port *uap = @@ -1793,9 +1802,10 @@ static int pl011_allocate_irq(struct uart_amba_port *uap) */ static void pl011_enable_interrupts(struct uart_amba_port *uap) { + unsigned long flags; unsigned int i; - spin_lock_irq(&uap->port.lock); + spin_lock_irqsave(&uap->port.lock, flags); /* Clear out any spuriously appearing RX interrupts */ pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); @@ -1817,7 +1827,14 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; pl011_write(uap->im, uap, REG_IMSC); - spin_unlock_irq(&uap->port.lock); + spin_unlock_irqrestore(&uap->port.lock, flags); +} + +static void pl011_unthrottle_rx(struct uart_port *port) +{ + struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + + pl011_enable_interrupts(uap); } static int pl011_startup(struct uart_port *port) @@ -2245,6 +2262,8 @@ static const struct uart_ops amba_pl011_pops = { .stop_tx = pl011_stop_tx, .start_tx = pl011_start_tx, .stop_rx = pl011_stop_rx, + .throttle = pl011_throttle_rx, + .unthrottle = pl011_unthrottle_rx, .enable_ms = pl011_enable_ms, .break_ctl = pl011_break_ctl, .startup = pl011_startup, diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index dd350c590880..c0a86558ceaa 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -295,20 +295,16 @@ static int atmel_config_rs485(struct uart_port *port, mode = atmel_uart_readl(port, ATMEL_US_MR); - /* Resetting serial mode to RS232 (0x0) */ - mode &= ~ATMEL_US_USMODE; - - port->rs485 = *rs485conf; - if (rs485conf->flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); - if (port->rs485.flags & SER_RS485_RX_DURING_TX) + if (rs485conf->flags & SER_RS485_RX_DURING_TX) atmel_port->tx_done_mask = ATMEL_US_TXRDY; else atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; atmel_uart_writel(port, ATMEL_US_TTGR, rs485conf->delay_rts_after_send); + mode &= ~ATMEL_US_USMODE; mode |= ATMEL_US_USMODE_RS485; } else { dev_dbg(port->dev, "Setting UART to RS232\n"); diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index ef95abf3342c..dc7ccdb16de8 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1500,9 +1500,9 @@ static int lpuart_config_rs485(struct uart_port *port, * Note: UART is assumed to be active high. */ if (rs485->flags & SER_RS485_RTS_ON_SEND) - modem &= ~UARTMODEM_TXRTSPOL; - else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) modem |= UARTMODEM_TXRTSPOL; + else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + modem &= ~UARTMODEM_TXRTSPOL; } /* Store the new configuration */ diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index b199d7859961..07c4161eb4cc 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -341,7 +341,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) LPC32XX_HSUART_IIR(port->membase)); port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); - tty_schedule_flip(tport); + tty_flip_buffer_push(tport); } /* Data received? */ diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index ab226da75f7b..1074a0fdf7a1 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -237,6 +237,7 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) struct tty_port *tport = &port->state->port; unsigned char ch = 0; char flag = 0; + int ret; do { if (status & STAT_RX_RDY(port)) { @@ -249,6 +250,16 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status) port->icount.parity++; } + /* + * For UART2, error bits are not cleared on buffer read. + * This causes interrupt loop and system hang. + */ + if (IS_EXTENDED(port) && (status & STAT_BRK_ERR)) { + ret = readl(port->membase + UART_STAT); + ret |= STAT_BRK_ERR; + writel(ret, port->membase + UART_STAT); + } + if (status & STAT_BRK_DET) { port->icount.brk++; status &= ~(STAT_FRM_ERR | STAT_PAR_ERR); @@ -442,13 +453,13 @@ static void mvebu_uart_shutdown(struct uart_port *port) } } -static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) +static unsigned int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) { unsigned int d_divisor, m_divisor; u32 brdv, osamp; if (!port->uartclk) - return -EOPNOTSUPP; + return 0; /* * The baudrate is derived from the UART clock thanks to two divisors: @@ -472,7 +483,7 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) osamp &= ~OSAMP_DIVISORS_MASK; writel(osamp, port->membase + UART_OSAMP); - return 0; + return DIV_ROUND_CLOSEST(port->uartclk, d_divisor * m_divisor); } static void mvebu_uart_set_termios(struct uart_port *port, @@ -509,15 +520,11 @@ static void mvebu_uart_set_termios(struct uart_port *port, max_baud = 230400; baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud); - if (mvebu_uart_baud_rate_set(port, baud)) { - /* No clock available, baudrate cannot be changed */ - if (old) - baud = uart_get_baud_rate(port, old, NULL, - min_baud, max_baud); - } else { - tty_termios_encode_baud_rate(termios, baud, baud); - uart_update_timeout(port, termios->c_cflag, baud); - } + baud = mvebu_uart_baud_rate_set(port, baud); + + /* In case baudrate cannot be changed, report previous old value */ + if (baud == 0 && old) + baud = tty_termios_baud_rate(old); /* Only the following flag changes are supported */ if (old) { @@ -528,6 +535,11 @@ static void mvebu_uart_set_termios(struct uart_port *port, termios->c_cflag |= CS8; } + if (baud != 0) { + tty_termios_encode_baud_rate(termios, baud, baud); + uart_update_timeout(port, termios->c_cflag, baud); + } + spin_unlock_irqrestore(&port->lock, flags); } diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 319533b3c32a..f460b47ff6f2 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -378,8 +378,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport) /* Enable tx dma mode */ ucon = rd_regl(port, S3C2410_UCON); ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK); - ucon |= (dma_get_cache_alignment() >= 16) ? - S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1; + ucon |= S3C64XX_UCON_TXBURST_1; ucon |= S3C64XX_UCON_TXMODE_DMA; wr_regl(port, S3C2410_UCON, ucon); @@ -675,7 +674,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport) S3C64XX_UCON_DMASUS_EN | S3C64XX_UCON_TIMEOUT_EN | S3C64XX_UCON_RXMODE_MASK); - ucon |= S3C64XX_UCON_RXBURST_16 | + ucon |= S3C64XX_UCON_RXBURST_1 | 0xf << S3C64XX_UCON_TIMEOUT_SHIFT | S3C64XX_UCON_EMPTYINT_EN | S3C64XX_UCON_TIMEOUT_EN | diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 4d3ad4c6c60f..82ddbb92d07d 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1912,11 +1912,6 @@ static int uart_proc_show(struct seq_file *m, void *v) } #endif -static inline bool uart_console_enabled(struct uart_port *port) -{ - return uart_console(port) && (port->cons->flags & CON_ENABLED); -} - static void uart_port_spin_lock_init(struct uart_port *port) { spin_lock_init(&port->lock); diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 10e9f983de62..fc166cc2c856 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -71,6 +71,8 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, *cr3 |= USART_CR3_DEM; over8 = *cr1 & USART_CR1_OVER8; + *cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + if (over8) rs485_deat_dedt = delay_ADE * baud * 8; else diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 6000853973c1..3cc9ef08455c 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -1137,6 +1137,8 @@ static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l) /* No compatible property, so try the name. */ soc_string = np->name; + of_node_put(np); + /* Extract the SOC number from the "PowerPC," string */ if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc) return 0; diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h index b710c5ef89ab..f310a8274df1 100644 --- a/drivers/tty/tty.h +++ b/drivers/tty/tty.h @@ -111,4 +111,7 @@ static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch) ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *); +int tty_insert_flip_string_and_push_buffer(struct tty_port *port, + const unsigned char *chars, size_t cnt); + #endif diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 6127f84b92b1..f3143ae4bf7f 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -403,27 +403,6 @@ int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) EXPORT_SYMBOL(__tty_insert_flip_char); /** - * tty_schedule_flip - push characters to ldisc - * @port: tty port to push from - * - * Takes any pending buffers and transfers their ownership to the - * ldisc side of the queue. It then schedules those characters for - * processing by the line discipline. - */ - -void tty_schedule_flip(struct tty_port *port) -{ - struct tty_bufhead *buf = &port->buf; - - /* paired w/ acquire in flush_to_ldisc(); ensures - * flush_to_ldisc() sees buffer data. - */ - smp_store_release(&buf->tail->commit, buf->tail->used); - queue_work(system_unbound_wq, &buf->work); -} -EXPORT_SYMBOL(tty_schedule_flip); - -/** * tty_prepare_flip_string - make room for characters * @port: tty port * @chars: return pointer for character write area @@ -554,6 +533,15 @@ static void flush_to_ldisc(struct work_struct *work) } +static inline void tty_flip_buffer_commit(struct tty_buffer *tail) +{ + /* + * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees + * buffer data. + */ + smp_store_release(&tail->commit, tail->used); +} + /** * tty_flip_buffer_push - terminal * @port: tty port to push @@ -567,11 +555,45 @@ static void flush_to_ldisc(struct work_struct *work) void tty_flip_buffer_push(struct tty_port *port) { - tty_schedule_flip(port); + struct tty_bufhead *buf = &port->buf; + + tty_flip_buffer_commit(buf->tail); + queue_work(system_unbound_wq, &buf->work); } EXPORT_SYMBOL(tty_flip_buffer_push); /** + * tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and + * push + * @port: tty port + * @chars: characters + * @size: size + * + * The function combines tty_insert_flip_string() and tty_flip_buffer_push() + * with the exception of properly holding the @port->lock. + * + * To be used only internally (by pty currently). + * + * Returns: the number added. + */ +int tty_insert_flip_string_and_push_buffer(struct tty_port *port, + const unsigned char *chars, size_t size) +{ + struct tty_bufhead *buf = &port->buf; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + size = tty_insert_flip_string(port, chars, size); + if (size) + tty_flip_buffer_commit(buf->tail); + spin_unlock_irqrestore(&port->lock, flags); + + queue_work(system_unbound_wq, &buf->work); + + return size; +} + +/** * tty_buffer_init - prepare a tty buffer structure * @port: tty port to initialise * diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index c7fbbcdcc346..3700cd057f27 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -324,13 +324,13 @@ int kbd_rate(struct kbd_repeat *rpt) static void put_queue(struct vc_data *vc, int ch) { tty_insert_flip_char(&vc->port, ch, 0); - tty_schedule_flip(&vc->port); + tty_flip_buffer_push(&vc->port); } static void puts_queue(struct vc_data *vc, const char *cp) { tty_insert_flip_string(&vc->port, cp, strlen(cp)); - tty_schedule_flip(&vc->port); + tty_flip_buffer_push(&vc->port); } static void applkey(struct vc_data *vc, int key, char mode) @@ -584,7 +584,7 @@ static void fn_inc_console(struct vc_data *vc) static void fn_send_intr(struct vc_data *vc) { tty_insert_flip_char(&vc->port, 0, TTY_BREAK); - tty_schedule_flip(&vc->port); + tty_flip_buffer_push(&vc->port); } static void fn_scroll_forw(struct vc_data *vc) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 7359c3e80d63..b8f5bc19416d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -344,7 +344,7 @@ static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows) /* allocate everything in one go */ memsize = cols * rows * sizeof(char32_t); memsize += rows * sizeof(char32_t *); - p = vmalloc(memsize); + p = vzalloc(memsize); if (!p) return NULL; @@ -855,7 +855,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr) unsigned short *p = (unsigned short *) vc->vc_pos; vc_uniscr_delete(vc, nr); - scr_memcpyw(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2); + scr_memmovew(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2); scr_memsetw(p + vc->vc_cols - vc->state.x - nr, vc->vc_video_erase_char, nr * 2); vc->vc_need_wrap = 0; @@ -1833,7 +1833,7 @@ static void csi_m(struct vc_data *vc) static void respond_string(const char *p, size_t len, struct tty_port *port) { tty_insert_flip_string(port, p, len); - tty_schedule_flip(port); + tty_flip_buffer_push(port); } static void cursor_report(struct vc_data *vc, struct tty_struct *tty) @@ -4662,9 +4662,11 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op) console_lock(); if (vc->vc_mode != KD_TEXT) rc = -EINVAL; - else if (vc->vc_sw->con_font_set) + else if (vc->vc_sw->con_font_set) { + if (vc_is_sel(vc)) + clear_selection(); rc = vc->vc_sw->con_font_set(vc, &font, op->flags); - else + } else rc = -ENOSYS; console_unlock(); kfree(font.data); @@ -4691,9 +4693,11 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) console_unlock(); return -EINVAL; } - if (vc->vc_sw->con_font_default) + if (vc->vc_sw->con_font_default) { + if (vc_is_sel(vc)) + clear_selection(); rc = vc->vc_sw->con_font_default(vc, &font, s); - else + } else rc = -ENOSYS; console_unlock(); if (!rc) { |