From 1c055e55a242a33e574e48be530e06770a210dcd Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 19 Feb 2024 03:26:26 +0000 Subject: [PATCH] add r8169 read mac form eeprom --- kernel/drivers/tty/n_tty.c | 217 +++++++++++++++++++++++++++++++++-------------------- 1 files changed, 135 insertions(+), 82 deletions(-) diff --git a/kernel/drivers/tty/n_tty.c b/kernel/drivers/tty/n_tty.c index 1b237ac..8e7931d 100644 --- a/kernel/drivers/tty/n_tty.c +++ b/kernel/drivers/tty/n_tty.c @@ -49,9 +49,12 @@ #include <linux/module.h> #include <linux/ratelimit.h> #include <linux/vmalloc.h> +#include "tty.h" - -/* number of characters left in xmit buffer before select has we have room */ +/* + * Until this number of characters is queued in the xmit buffer, select will + * return "we have room for writes". + */ #define WAKEUP_CHARS 256 /* @@ -82,7 +85,7 @@ #ifdef N_TTY_TRACE # define n_tty_trace(f, args...) trace_printk(f, ##args) #else -# define n_tty_trace(f, args...) +# define n_tty_trace(f, args...) no_printk(f, ##args) #endif struct n_tty_data { @@ -162,29 +165,24 @@ memset(buffer, 0x00, size); } -static int tty_copy_to_user(struct tty_struct *tty, void __user *to, - size_t tail, size_t n) +static void tty_copy(struct tty_struct *tty, void *to, size_t tail, size_t n) { struct n_tty_data *ldata = tty->disc_data; size_t size = N_TTY_BUF_SIZE - tail; void *from = read_buf_addr(ldata, tail); - int uncopied; if (n > size) { tty_audit_add_data(tty, from, size); - uncopied = copy_to_user(to, from, size); - zero_buffer(tty, from, size - uncopied); - if (uncopied) - return uncopied; + memcpy(to, from, size); + zero_buffer(tty, from, size); to += size; n -= size; from = ldata->read_buf; } tty_audit_add_data(tty, from, n); - uncopied = copy_to_user(to, from, n); - zero_buffer(tty, from, n - uncopied); - return uncopied; + memcpy(to, from, n); + zero_buffer(tty, from, n); } /** @@ -320,7 +318,7 @@ /** * reset_buffer_flags - reset buffer state - * @tty: terminal to reset + * @ldata: line disc data to reset * * Reset the read buffer counters and clear the flags. * Called from n_tty_open() and n_tty_flush_buffer(). @@ -548,9 +546,9 @@ mutex_lock(&ldata->output_lock); space = tty_write_room(tty); - if (!space) { + if (space <= 0) { mutex_unlock(&ldata->output_lock); - return 0; + return space; } if (nr > space) nr = space; @@ -652,9 +650,9 @@ op = echo_buf(ldata, tail + 1); switch (op) { + case ECHO_OP_ERASE_TAB: { unsigned int num_chars, num_bs; - case ECHO_OP_ERASE_TAB: if (MASK(ldata->echo_commit) == MASK(tail + 2)) goto not_yet_stored; num_chars = echo_buf(ldata, tail + 2); @@ -685,7 +683,7 @@ } tail += 3; break; - + } case ECHO_OP_SET_CANON_COL: ldata->canon_column = ldata->column; tail += 2; @@ -904,7 +902,7 @@ /** * echo_char_raw - echo a character raw * @c: unicode byte to echo - * @tty: terminal device + * @ldata: line disc data * * Echo user input back onto the screen. This must be called only when * L_ECHO(tty) is true. Called from the driver receive_buf path. @@ -1940,42 +1938,38 @@ /** * copy_from_read_buf - copy read data directly * @tty: terminal device - * @b: user data + * @kbp: data * @nr: size of data * * Helper function to speed up n_tty_read. It is only called when - * ICANON is off; it copies characters straight from the tty queue to - * user space directly. It can be profitably called twice; once to - * drain the space from the tail pointer to the (physical) end of the - * buffer, and once to drain the space from the (physical) beginning of - * the buffer to head pointer. + * ICANON is off; it copies characters straight from the tty queue. * * Called under the ldata->atomic_read_lock sem + * + * Returns true if it successfully copied data, but there is still + * more data to be had. * * n_tty_read()/consumer path: * caller holds non-exclusive termios_rwsem * read_tail published */ -static int copy_from_read_buf(struct tty_struct *tty, - unsigned char __user **b, +static bool copy_from_read_buf(struct tty_struct *tty, + unsigned char **kbp, size_t *nr) { struct n_tty_data *ldata = tty->disc_data; - int retval; size_t n; bool is_eof; size_t head = smp_load_acquire(&ldata->commit_head); size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1); - retval = 0; n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail); n = min(*nr, n); if (n) { unsigned char *from = read_buf_addr(ldata, tail); - retval = copy_to_user(*b, from, n); - n -= retval; + memcpy(*kbp, from, n); is_eof = n == 1 && *from == EOF_CHAR(tty); tty_audit_add_data(tty, from, n); zero_buffer(tty, from, n); @@ -1983,22 +1977,25 @@ /* Turn single EOF into zero-length read */ if (L_EXTPROC(tty) && ldata->icanon && is_eof && (head == ldata->read_tail)) - n = 0; - *b += n; + return false; + *kbp += n; *nr -= n; + + /* If we have more to copy, let the caller know */ + return head != ldata->read_tail; } - return retval; + return false; } /** * canon_copy_from_read_buf - copy read data in canonical mode * @tty: terminal device - * @b: user data + * @kbp: data * @nr: size of data * * Helper function for n_tty_read. It is only called when ICANON is on; * it copies one line of input up to and including the line-delimiting - * character into the user-space buffer. + * character into the result buffer. * * NB: When termios is changed from non-canonical to canonical mode and * the read buffer contains data, n_tty_set_termios() simulates an EOF @@ -2013,21 +2010,22 @@ * read_tail published */ -static int canon_copy_from_read_buf(struct tty_struct *tty, - unsigned char __user **b, - size_t *nr) +static bool canon_copy_from_read_buf(struct tty_struct *tty, + unsigned char **kbp, + size_t *nr) { struct n_tty_data *ldata = tty->disc_data; size_t n, size, more, c; size_t eol; - size_t tail; - int ret, found = 0; + size_t tail, canon_head; + int found = 0; /* N.B. avoid overrun if nr == 0 */ if (!*nr) - return 0; + return false; - n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail); + canon_head = smp_load_acquire(&ldata->canon_head); + n = min(*nr, canon_head - ldata->read_tail); tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1); size = min_t(size_t, tail + n, N_TTY_BUF_SIZE); @@ -2049,18 +2047,14 @@ n += N_TTY_BUF_SIZE; c = n + found; - if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) { - c = min(*nr, c); + if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) n = c; - } n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n", __func__, eol, found, n, c, tail, more); - ret = tty_copy_to_user(tty, *b, tail, n); - if (ret) - return -EFAULT; - *b += n; + tty_copy(tty, *kbp, tail, n); + *kbp += n; *nr -= n; if (found) @@ -2073,12 +2067,41 @@ else ldata->push = 0; tty_audit_push(); + return false; } - return 0; + + /* No EOL found - do a continuation retry if there is more data */ + return ldata->read_tail != canon_head; } -extern ssize_t redirected_tty_write(struct file *, const char __user *, - size_t, loff_t *); +/* + * If we finished a read at the exact location of an + * EOF (special EOL character that's a __DISABLED_CHAR) + * in the stream, silently eat the EOF. + */ +static void canon_skip_eof(struct tty_struct *tty) +{ + struct n_tty_data *ldata = tty->disc_data; + size_t tail, canon_head; + + canon_head = smp_load_acquire(&ldata->canon_head); + tail = ldata->read_tail; + + // No data? + if (tail == canon_head) + return; + + // See if the tail position is EOF in the circular buffer + tail &= (N_TTY_BUF_SIZE - 1); + if (!test_bit(tail, ldata->read_flags)) + return; + if (read_buf(ldata, tail) != __DISABLED_CHAR) + return; + + // Clear the EOL bit, skip the EOF char. + clear_bit(tail, ldata->read_flags); + smp_store_release(&ldata->read_tail, ldata->read_tail + 1); +} /** * job_control - check job control @@ -2101,7 +2124,7 @@ /* NOTE: not yet done after every sleep pending a thorough check of the logic of this change. -- jlc */ /* don't stop on /dev/console */ - if (file->f_op->write == redirected_tty_write) + if (file->f_op->write_iter == redirected_tty_write) return 0; return __tty_check_change(tty, SIGTTIN); @@ -2128,10 +2151,11 @@ */ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) + unsigned char *kbuf, size_t nr, + void **cookie, unsigned long offset) { struct n_tty_data *ldata = tty->disc_data; - unsigned char __user *b = buf; + unsigned char *kb = kbuf; DEFINE_WAIT_FUNC(wait, woken_wake_function); int c; int minimum, time; @@ -2139,6 +2163,37 @@ long timeout; int packet; size_t tail; + + /* + * Is this a continuation of a read started earler? + * + * If so, we still hold the atomic_read_lock and the + * termios_rwsem, and can just continue to copy data. + */ + if (*cookie) { + if (ldata->icanon && !L_EXTPROC(tty)) { + /* + * If we have filled the user buffer, see + * if we should skip an EOF character before + * releasing the lock and returning done. + */ + if (!nr) + canon_skip_eof(tty); + else if (canon_copy_from_read_buf(tty, &kb, &nr)) + return kb - kbuf; + } else { + if (copy_from_read_buf(tty, &kb, &nr)) + return kb - kbuf; + } + + /* No more data - release locks and stop retries */ + n_tty_kick_worker(tty); + n_tty_check_unthrottle(tty); + up_read(&tty->termios_rwsem); + mutex_unlock(&ldata->atomic_read_lock); + *cookie = NULL; + return kb - kbuf; + } c = job_control(tty, file); if (c < 0) @@ -2177,17 +2232,13 @@ /* First test for status change. */ if (packet && tty->link->ctrl_status) { unsigned char cs; - if (b != buf) + if (kb != kbuf) break; spin_lock_irq(&tty->link->ctrl_lock); cs = tty->link->ctrl_status; tty->link->ctrl_status = 0; spin_unlock_irq(&tty->link->ctrl_lock); - if (put_user(cs, b)) { - retval = -EFAULT; - break; - } - b++; + *kb++ = cs; nr--; break; } @@ -2230,33 +2281,35 @@ } if (ldata->icanon && !L_EXTPROC(tty)) { - retval = canon_copy_from_read_buf(tty, &b, &nr); - if (retval) - break; + if (canon_copy_from_read_buf(tty, &kb, &nr)) + goto more_to_be_read; } else { - int uncopied; - /* Deal with packet mode. */ - if (packet && b == buf) { - if (put_user(TIOCPKT_DATA, b)) { - retval = -EFAULT; - break; - } - b++; + if (packet && kb == kbuf) { + *kb++ = TIOCPKT_DATA; nr--; } - uncopied = copy_from_read_buf(tty, &b, &nr); - uncopied += copy_from_read_buf(tty, &b, &nr); - if (uncopied) { - retval = -EFAULT; - break; + /* + * Copy data, and if there is more to be had + * and we have nothing more to wait for, then + * let's mark us for retries. + * + * NOTE! We return here with both the termios_sem + * and atomic_read_lock still held, the retries + * will release them when done. + */ + if (copy_from_read_buf(tty, &kb, &nr) && kb - kbuf >= minimum) { +more_to_be_read: + remove_wait_queue(&tty->read_wait, &wait); + *cookie = cookie; + return kb - kbuf; } } n_tty_check_unthrottle(tty); - if (b - buf >= minimum) + if (kb - kbuf >= minimum) break; if (time) timeout = time; @@ -2268,8 +2321,8 @@ remove_wait_queue(&tty->read_wait, &wait); mutex_unlock(&ldata->atomic_read_lock); - if (b - buf) - retval = b - buf; + if (kb - kbuf) + retval = kb - kbuf; return retval; } @@ -2305,7 +2358,7 @@ ssize_t retval = 0; /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ - if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) { + if (L_TOSTOP(tty) && file->f_op->write_iter != redirected_tty_write) { retval = tty_check_change(tty); if (retval) return retval; -- Gitblit v1.6.2