summaryrefslogtreecommitdiffstats
path: root/drivers/s390/char
diff options
context:
space:
mode:
authorSven Schnelle <svens@linux.ibm.com>2022-11-28 11:34:52 +0100
committerHeiko Carstens <hca@linux.ibm.com>2023-01-09 14:34:01 +0100
commit76485078702ae680c9683500ad9caafea05678b1 (patch)
treedf557c6cf1e5238204dada23794ce2f2984a5705 /drivers/s390/char
parent164eb669348045894b50eaecc5936ec07b4307f0 (diff)
downloadlinux-stable-76485078702ae680c9683500ad9caafea05678b1.tar.gz
linux-stable-76485078702ae680c9683500ad9caafea05678b1.tar.bz2
linux-stable-76485078702ae680c9683500ad9caafea05678b1.zip
s390/con3270: rewrite command line recalling
Command line recalling is the last user of the 3270 custom malloc() like allocator. Remove this dependency by using a statically allocated buffer for the saved command lines, and also remove the allocator. Signed-off-by: Sven Schnelle <svens@linux.ibm.com> Acked-by: Heiko Carstens <hca@linux.ibm.com> Tested-by: Niklas Schnelle <schnelle@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Diffstat (limited to 'drivers/s390/char')
-rw-r--r--drivers/s390/char/con3270.c165
-rw-r--r--drivers/s390/char/raw3270.h79
2 files changed, 74 insertions, 170 deletions
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index e3eee0492fea..71012c20ec7b 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -34,9 +34,8 @@
#define TTY3270_CHAR_BUF_SIZE 256
#define TTY3270_OUTPUT_BUFFER_SIZE 4096
-#define TTY3270_STRING_PAGES 5
-
#define TTY3270_SCREEN_PAGES 8 /* has to be power-of-two */
+#define TTY3270_RECALL_SIZE 16 /* has to be power-of-two */
static struct tty_driver *tty3270_driver;
static int tty3270_max_index;
@@ -77,13 +76,9 @@ static const unsigned char sfq_read_partition[] = {
struct tty3270 {
struct raw3270_view view;
struct tty_port port;
- void **freemem_pages; /* Array of pages used for freemem. */
- struct list_head freemem; /* List of free memory for strings. */
/* Output stuff. */
- struct list_head lines; /* List of lines. */
unsigned char wcc; /* Write control character. */
- int nr_lines; /* # lines in list. */
int nr_up; /* # lines up in history. */
unsigned long update_flags; /* Update indication bits. */
struct raw3270_request *write; /* Single write request. */
@@ -117,9 +112,9 @@ struct tty3270 {
unsigned int saved_cx, saved_cy;
/* Command recalling. */
- struct list_head rcl_lines; /* List of recallable lines. */
- struct list_head *rcl_walk; /* Point in rcl_lines list. */
- int rcl_nr, rcl_max; /* Number/max number of rcl_lines. */
+ char **rcl_lines; /* Array of recallable lines */
+ int rcl_write_index; /* Write index of recallable items */
+ int rcl_read_index; /* Read index of recallable items */
/* Character array for put_char/flush_chars. */
unsigned int char_count;
@@ -203,10 +198,9 @@ static int tty3270_input_size(int cols)
return cols * 2 - 11;
}
-static void tty3270_update_prompt(struct tty3270 *tp, char *input, int count)
+static void tty3270_update_prompt(struct tty3270 *tp, char *input)
{
- memcpy(tp->prompt, input, count);
- tp->prompt[count] = '\0';
+ strcpy(tp->prompt, input);
tp->update_flags |= TTY_UPDATE_INPUT;
tty3270_set_timer(tp, 1);
}
@@ -271,25 +265,6 @@ static void tty3270_update_string(struct tty3270 *tp, char *line, int len, int n
raw3270_buffer_address(tp->view.dev, cp + 1, 0, nr + 1);
}
-/*
- * Alloc string for size bytes. If there is not enough room in
- * freemem, free strings until there is room.
- */
-static struct string *tty3270_alloc_string(struct tty3270 *tp, size_t size)
-{
- struct string *s, *n;
-
- s = alloc_string(&tp->freemem, size);
- if (s)
- return s;
- list_for_each_entry_safe(s, n, &tp->lines, list) {
- list_del(&s->list);
- if (free_string(&tp->freemem, s) >= size)
- break;
- }
- return alloc_string(&tp->freemem, size);
-}
-
static void tty3270_blank_screen(struct tty3270 *tp)
{
struct tty3270_line *line;
@@ -542,44 +517,29 @@ static void tty3270_update(struct timer_list *t)
*/
static void tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
{
- struct string *s;
-
- tp->rcl_walk = NULL;
+ char *p;
if (len <= 0)
return;
- if (tp->rcl_nr >= tp->rcl_max) {
- s = list_entry(tp->rcl_lines.next, struct string, list);
- list_del(&s->list);
- free_string(&tp->freemem, s);
- tp->rcl_nr--;
- }
- s = tty3270_alloc_string(tp, len);
- if (!s)
- return;
- memcpy(s->string, input, len);
- list_add_tail(&s->list, &tp->rcl_lines);
- tp->rcl_nr++;
+ p = tp->rcl_lines[tp->rcl_write_index++];
+ tp->rcl_write_index &= TTY3270_RECALL_SIZE - 1;
+ memcpy(p, input, len);
+ p[len] = '\0';
+ tp->rcl_read_index = tp->rcl_write_index;
}
static void tty3270_rcl_backward(struct kbd_data *kbd)
{
struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
- struct string *s;
+ int i = 0;
spin_lock_irq(&tp->view.lock);
if (tp->inattr == TF_INPUT) {
- if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
- tp->rcl_walk = tp->rcl_walk->prev;
- else if (!list_empty(&tp->rcl_lines))
- tp->rcl_walk = tp->rcl_lines.prev;
- s = tp->rcl_walk ?
- list_entry(tp->rcl_walk, struct string, list) : NULL;
- if (tp->rcl_walk) {
- s = list_entry(tp->rcl_walk, struct string, list);
- tty3270_update_prompt(tp, s->string, s->len);
- } else
- tty3270_update_prompt(tp, NULL, 0);
- tty3270_set_timer(tp, 1);
+ do {
+ tp->rcl_read_index--;
+ tp->rcl_read_index &= TTY3270_RECALL_SIZE - 1;
+ } while (!*tp->rcl_lines[tp->rcl_read_index] &&
+ i++ < TTY3270_RECALL_SIZE - 1);
+ tty3270_update_prompt(tp, tp->rcl_lines[tp->rcl_read_index]);
}
spin_unlock_irq(&tp->view.lock);
}
@@ -664,7 +624,7 @@ static void tty3270_read_tasklet(unsigned long data)
if (tp->nr_up > 0)
tp->nr_up = 0;
/* Clear input area. */
- tty3270_update_prompt(tp, NULL, 0);
+ tty3270_update_prompt(tp, "");
tty3270_set_timer(tp, 1);
break;
case AID_CLEAR:
@@ -796,32 +756,14 @@ static void tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct i
static struct tty3270 *tty3270_alloc_view(void)
{
struct tty3270 *tp;
- int pages;
tp = kzalloc(sizeof(struct tty3270), GFP_KERNEL);
if (!tp)
goto out_err;
- tp->freemem_pages =
- kmalloc_array(TTY3270_STRING_PAGES, sizeof(void *),
- GFP_KERNEL);
- if (!tp->freemem_pages)
- goto out_tp;
- INIT_LIST_HEAD(&tp->freemem);
- INIT_LIST_HEAD(&tp->lines);
- INIT_LIST_HEAD(&tp->rcl_lines);
- tp->rcl_max = 20;
-
- for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
- tp->freemem_pages[pages] = (void *)
- __get_free_pages(GFP_KERNEL|GFP_DMA, 0);
- if (!tp->freemem_pages[pages])
- goto out_pages;
- add_string_memory(&tp->freemem,
- tp->freemem_pages[pages], PAGE_SIZE);
- }
+
tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE);
if (IS_ERR(tp->write))
- goto out_pages;
+ goto out_tp;
tp->read = raw3270_request_alloc(0);
if (IS_ERR(tp->read))
goto out_write;
@@ -851,11 +793,6 @@ out_read:
raw3270_request_free(tp->read);
out_write:
raw3270_request_free(tp->write);
-out_pages:
- while (pages--)
- free_pages((unsigned long) tp->freemem_pages[pages], 0);
- kfree(tp->freemem_pages);
- tty_port_destroy(&tp->port);
out_tp:
kfree(tp);
out_err:
@@ -867,15 +804,10 @@ out_err:
*/
static void tty3270_free_view(struct tty3270 *tp)
{
- int pages;
-
kbd_free(tp->kbd);
raw3270_request_free(tp->kreset);
raw3270_request_free(tp->read);
raw3270_request_free(tp->write);
- for (pages = 0; pages < TTY3270_STRING_PAGES; pages++)
- free_pages((unsigned long) tp->freemem_pages[pages], 0);
- kfree(tp->freemem_pages);
free_page((unsigned long)tp->converted_line);
tty_port_destroy(&tp->port);
kfree(tp);
@@ -909,6 +841,38 @@ out_err:
return ERR_PTR(-ENOMEM);
}
+static char **tty3270_alloc_recall(int cols)
+{
+ char **lines;
+ int i;
+
+ lines = kmalloc_array(TTY3270_RECALL_SIZE, sizeof(char *), GFP_KERNEL);
+ if (!lines)
+ return NULL;
+ for (i = 0; i < TTY3270_RECALL_SIZE; i++) {
+ lines[i] = kcalloc(1, tty3270_input_size(cols) + 1, GFP_KERNEL);
+ if (!lines[i])
+ break;
+ }
+
+ if (i == TTY3270_RECALL_SIZE)
+ return lines;
+
+ while (i--)
+ kfree(lines[i]);
+ kfree(lines);
+ return NULL;
+}
+
+static void tty3270_free_recall(char **lines)
+{
+ int i;
+
+ for (i = 0; i < TTY3270_RECALL_SIZE; i++)
+ kfree(lines[i]);
+ kfree(lines);
+}
+
/*
* Free tty3270 screen.
*/
@@ -930,6 +894,7 @@ static void tty3270_resize(struct raw3270_view *view,
{
struct tty3270 *tp = container_of(view, struct tty3270, view);
struct tty3270_line *screen, *oscreen;
+ char **old_rcl_lines, **new_rcl_lines;
char *old_prompt, *new_prompt;
char *old_input, *new_input;
struct tty_struct *tty;
@@ -954,6 +919,9 @@ static void tty3270_resize(struct raw3270_view *view,
screen = tty3270_alloc_screen(tp, new_rows, new_cols, &new_allocated);
if (IS_ERR(screen))
goto out_prompt;
+ new_rcl_lines = tty3270_alloc_recall(new_cols);
+ if (!new_rcl_lines)
+ goto out_screen;
/* Switch to new output size */
spin_lock_irq(&tp->view.lock);
@@ -967,12 +935,17 @@ static void tty3270_resize(struct raw3270_view *view,
tp->update_flags = TTY_UPDATE_ALL;
old_input = tp->input;
old_prompt = tp->prompt;
+ old_rcl_lines = tp->rcl_lines;
tp->input = new_input;
tp->prompt = new_prompt;
+ tp->rcl_lines = new_rcl_lines;
+ tp->rcl_read_index = 0;
+ tp->rcl_write_index = 0;
spin_unlock_irq(&tp->view.lock);
tty3270_free_screen(oscreen, old_allocated);
kfree(old_input);
kfree(old_prompt);
+ tty3270_free_recall(old_rcl_lines);
tty3270_set_timer(tp, 1);
/* Informat tty layer about new size */
tty = tty_port_tty_get(&tp->port);
@@ -983,6 +956,8 @@ static void tty3270_resize(struct raw3270_view *view,
tty_do_resize(tty, &ws);
tty_kref_put(tty);
return;
+out_screen:
+ tty3270_free_screen(screen, new_rows);
out_prompt:
kfree(new_prompt);
out_input:
@@ -1089,6 +1064,12 @@ tty3270_create_view(int index, struct tty3270 **newtp)
goto out_free_input;
}
+ tp->rcl_lines = tty3270_alloc_recall(tp->view.cols);
+ if (!tp->rcl_lines) {
+ rc = -ENOMEM;
+ goto out_free_prompt;
+ }
+
/* Create blank line for every line in the tty output area. */
tty3270_blank_screen(tp);
@@ -1104,6 +1085,8 @@ tty3270_create_view(int index, struct tty3270 **newtp)
*newtp = tp;
return 0;
+out_free_prompt:
+ kfree(tp->prompt);
out_free_input:
kfree(tp->input);
out_free_converted_line:
@@ -1813,7 +1796,7 @@ static void tty3270_set_termios(struct tty_struct *tty, const struct ktermios *o
new = L_ECHO(tty) ? TF_INPUT: TF_INPUTN;
if (new != tp->inattr) {
tp->inattr = new;
- tty3270_update_prompt(tp, NULL, 0);
+ tty3270_update_prompt(tp, "");
tty3270_set_timer(tp, 1);
}
}
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h
index 5ca1af6df935..19f2bc1ee72e 100644
--- a/drivers/s390/char/raw3270.h
+++ b/drivers/s390/char/raw3270.h
@@ -213,82 +213,3 @@ struct raw3270_notifier {
int raw3270_register_notifier(struct raw3270_notifier *);
void raw3270_unregister_notifier(struct raw3270_notifier *);
-/*
- * Little memory allocator for string objects.
- */
-struct string
-{
- struct list_head list;
- unsigned long size;
- unsigned long len;
- char string[];
-} __attribute__ ((aligned(8)));
-
-static inline struct string *
-alloc_string(struct list_head *free_list, unsigned long len)
-{
- struct string *cs, *tmp;
- unsigned long size;
-
- size = (len + 7L) & -8L;
- list_for_each_entry(cs, free_list, list) {
- if (cs->size < size)
- continue;
- if (cs->size > size + sizeof(struct string)) {
- char *endaddr = (char *) (cs + 1) + cs->size;
- tmp = (struct string *) (endaddr - size) - 1;
- tmp->size = size;
- cs->size -= size + sizeof(struct string);
- cs = tmp;
- } else
- list_del(&cs->list);
- cs->len = len;
- INIT_LIST_HEAD(&cs->list);
- return cs;
- }
- return NULL;
-}
-
-static inline unsigned long
-free_string(struct list_head *free_list, struct string *cs)
-{
- struct string *tmp;
- struct list_head *p, *left;
-
- /* Find out the left neighbour in free memory list. */
- left = free_list;
- list_for_each(p, free_list) {
- if (list_entry(p, struct string, list) > cs)
- break;
- left = p;
- }
- /* Try to merge with right neighbour = next element from left. */
- if (left->next != free_list) {
- tmp = list_entry(left->next, struct string, list);
- if ((char *) (cs + 1) + cs->size == (char *) tmp) {
- list_del(&tmp->list);
- cs->size += tmp->size + sizeof(struct string);
- }
- }
- /* Try to merge with left neighbour. */
- if (left != free_list) {
- tmp = list_entry(left, struct string, list);
- if ((char *) (tmp + 1) + tmp->size == (char *) cs) {
- tmp->size += cs->size + sizeof(struct string);
- return tmp->size;
- }
- }
- __list_add(&cs->list, left, left->next);
- return cs->size;
-}
-
-static inline void
-add_string_memory(struct list_head *free_list, void *mem, unsigned long size)
-{
- struct string *cs;
-
- cs = (struct string *) mem;
- cs->size = size - sizeof(struct string);
- free_string(free_list, cs);
-}
-