sticon/parisc: Fix STI console on 64-bit only machines
authorHelge Deller <deller@gmx.de>
Wed, 10 May 2023 20:17:27 +0000 (22:17 +0200)
committerHelge Deller <deller@gmx.de>
Fri, 30 Jun 2023 15:14:14 +0000 (17:14 +0200)
Fix the STI console to be able to execute either the 64-bit STI ROM code
or the 32-bit STI ROM code.

This is necessary on 64-bit only machines (e.g. C8000 workstation) which
otherwise won't show the STI text console with HP graphic cards like
Visualize-FX5/FX10/FXe.

Note that when calling 32-bit code from a 64-bit kernel one needs to
copy contents on the CPU stack from high memory down below the 4GB
limit.

Tested-by: John David Anglin <dave.anglin@bell.net>
Signed-off-by: Helge Deller <deller@gmx.de>
drivers/video/fbdev/stifb.c
drivers/video/sticore.c
include/video/sticore.h

index 66d82f6..c746deb 100644 (file)
@@ -71,9 +71,9 @@
 
 #include <video/sticore.h>
 
-/* REGION_BASE(fb_info, index) returns the virtual address for region <index> */
+/* REGION_BASE(fb_info, index) returns the physical address for region <index> */
 #define REGION_BASE(fb_info, index) \
-       F_EXTEND(fb_info->sti->glob_cfg->region_ptrs[index])
+       F_EXTEND(fb_info->sti->regions_phys[index])
 
 #define NGLEDEVDEPROM_CRT_REGION 1
 
index 60ba3ab..c3765ad 100644 (file)
@@ -4,7 +4,7 @@
  *     core code for console driver using HP's STI firmware
  *
  *     Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- *     Copyright (C) 2001-2020 Helge Deller <deller@gmx.de>
+ *     Copyright (C) 2001-2023 Helge Deller <deller@gmx.de>
  *     Copyright (C) 2001-2002 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
  *
  * TODO:
@@ -41,6 +41,26 @@ static struct sti_struct *default_sti __read_mostly;
 static int num_sti_roms __read_mostly;
 static struct sti_struct *sti_roms[MAX_STI_ROMS] __read_mostly;
 
+static void *store_sti_val(struct sti_struct *sti, void *ptr, unsigned long val)
+{
+       u32 *ptr32 = ptr;
+
+       if (IS_ENABLED(CONFIG_64BIT) && sti->do_call64) {
+               /* used for 64-bit STI ROM */
+               unsigned long *ptr64 = ptr;
+
+               ptr64 = PTR_ALIGN(ptr64, sizeof(void *));
+               *ptr64++ = val;
+               return ptr64;
+       }
+
+       /* used for 32-bit STI ROM */
+       *ptr32++ = val;
+       return ptr32;
+}
+
+#define store_sti_ptr(sti, dest, ptr)  \
+               store_sti_val(sti, dest, STI_PTR(ptr))
 
 /* The colour indices used by STI are
  *   0 - Black
@@ -87,7 +107,7 @@ static int sti_init_graph(struct sti_struct *sti)
        memset(inptr, 0, sizeof(*inptr));
        inptr->text_planes = 3; /* # of text planes (max 3 for STI) */
        memset(inptr_ext, 0, sizeof(*inptr_ext));
-       inptr->ext_ptr = STI_PTR(inptr_ext);
+       store_sti_ptr(sti, &inptr->ext_ptr, inptr_ext);
        outptr->errno = 0;
 
        ret = sti_call(sti, sti->init_graph, &default_init_flags, inptr,
@@ -118,7 +138,7 @@ static void sti_inq_conf(struct sti_struct *sti)
        unsigned long flags;
        s32 ret;
 
-       outptr->ext_ptr = STI_PTR(&sti->sti_data->inq_outptr_ext);
+       store_sti_ptr(sti, &outptr->ext_ptr, &sti->sti_data->inq_outptr_ext);
 
        do {
                spin_lock_irqsave(&sti->lock, flags);
@@ -138,9 +158,9 @@ void
 sti_putc(struct sti_struct *sti, int c, int y, int x,
         struct sti_cooked_font *font)
 {
-       struct sti_font_inptr *inptr = &sti->sti_data->font_inptr;
+       struct sti_font_inptr *inptr;
        struct sti_font_inptr inptr_default = {
-               .font_start_addr = STI_PTR(font->raw),
+               .font_start_addr = (void *)STI_PTR(font->raw),
                .index          = c_index(sti, c),
                .fg_color       = c_fg(sti, c),
                .bg_color       = c_bg(sti, c),
@@ -153,7 +173,14 @@ sti_putc(struct sti_struct *sti, int c, int y, int x,
 
        do {
                spin_lock_irqsave(&sti->lock, flags);
-               *inptr = inptr_default;
+               inptr = &inptr_default;
+               if (IS_ENABLED(CONFIG_64BIT) && !sti->do_call64) {
+                       /* copy below 4G if calling 32-bit on LP64 kernel */
+                       inptr = &sti->sti_data->font_inptr;
+                       *inptr = inptr_default;
+                       /* skip first 4 bytes for 32-bit STI call */
+                       inptr = (void *)(((unsigned long)inptr) + sizeof(u32));
+               }
                ret = sti_call(sti, sti->font_unpmv, &default_font_flags,
                        inptr, outptr, sti->glob_cfg);
                spin_unlock_irqrestore(&sti->lock, flags);
@@ -170,7 +197,7 @@ void
 sti_set(struct sti_struct *sti, int src_y, int src_x,
        int height, int width, u8 color)
 {
-       struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr;
+       struct sti_blkmv_inptr *inptr;
        struct sti_blkmv_inptr inptr_default = {
                .fg_color       = color,
                .bg_color       = color,
@@ -187,7 +214,12 @@ sti_set(struct sti_struct *sti, int src_y, int src_x,
 
        do {
                spin_lock_irqsave(&sti->lock, flags);
-               *inptr = inptr_default;
+               inptr = &inptr_default;
+               if (IS_ENABLED(CONFIG_64BIT) && !sti->do_call64) {
+                       /* copy below 4G if calling 32-bit on LP64 kernel */
+                       inptr = &sti->sti_data->blkmv_inptr;
+                       *inptr = inptr_default;
+               }
                ret = sti_call(sti, sti->block_move, &clear_blkmv_flags,
                        inptr, outptr, sti->glob_cfg);
                spin_unlock_irqrestore(&sti->lock, flags);
@@ -198,7 +230,7 @@ void
 sti_clear(struct sti_struct *sti, int src_y, int src_x,
          int height, int width, int c, struct sti_cooked_font *font)
 {
-       struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr;
+       struct sti_blkmv_inptr *inptr;
        struct sti_blkmv_inptr inptr_default = {
                .fg_color       = c_fg(sti, c),
                .bg_color       = c_bg(sti, c),
@@ -215,7 +247,12 @@ sti_clear(struct sti_struct *sti, int src_y, int src_x,
 
        do {
                spin_lock_irqsave(&sti->lock, flags);
-               *inptr = inptr_default;
+               inptr = &inptr_default;
+               if (IS_ENABLED(CONFIG_64BIT) && !sti->do_call64) {
+                       /* copy below 4G if calling 32-bit on LP64 kernel */
+                       inptr = &sti->sti_data->blkmv_inptr;
+                       *inptr = inptr_default;
+               }
                ret = sti_call(sti, sti->block_move, &clear_blkmv_flags,
                        inptr, outptr, sti->glob_cfg);
                spin_unlock_irqrestore(&sti->lock, flags);
@@ -231,7 +268,7 @@ sti_bmove(struct sti_struct *sti, int src_y, int src_x,
          int dst_y, int dst_x, int height, int width,
          struct sti_cooked_font *font)
 {
-       struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr;
+       struct sti_blkmv_inptr *inptr;
        struct sti_blkmv_inptr inptr_default = {
                .src_x          = src_x * font->width,
                .src_y          = src_y * font->height,
@@ -246,7 +283,12 @@ sti_bmove(struct sti_struct *sti, int src_y, int src_x,
 
        do {
                spin_lock_irqsave(&sti->lock, flags);
-               *inptr = inptr_default;
+               inptr = &inptr_default;
+               if (IS_ENABLED(CONFIG_64BIT) && !sti->do_call64) {
+                       /* copy below 4G if calling 32-bit on LP64 kernel */
+                       inptr = &sti->sti_data->blkmv_inptr;
+                       *inptr = inptr_default;
+               }
                ret = sti_call(sti, sti->block_move, &default_blkmv_flags,
                        inptr, outptr, sti->glob_cfg);
                spin_unlock_irqrestore(&sti->lock, flags);
@@ -359,42 +401,31 @@ __setup("sti_font=", sti_font_setup);
 
 
 
-static void sti_dump_globcfg(struct sti_glob_cfg *glob_cfg,
-                            unsigned int sti_mem_request)
+static void sti_dump_globcfg(struct sti_struct *sti)
 {
-       struct sti_glob_cfg_ext *cfg;
+       struct sti_glob_cfg *glob_cfg = sti->glob_cfg;
+       struct sti_glob_cfg_ext *cfg = &sti->sti_data->glob_cfg_ext;
 
        pr_debug("%d text planes\n"
                "%4d x %4d screen resolution\n"
                "%4d x %4d offscreen\n"
-               "%4d x %4d layout\n"
-               "regions at %08x %08x %08x %08x\n"
-               "regions at %08x %08x %08x %08x\n"
-               "reent_lvl %d\n"
-               "save_addr %08x\n",
+               "%4d x %4d layout\n",
                glob_cfg->text_planes,
                glob_cfg->onscreen_x, glob_cfg->onscreen_y,
                glob_cfg->offscreen_x, glob_cfg->offscreen_y,
-               glob_cfg->total_x, glob_cfg->total_y,
-               glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
-               glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
-               glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
-               glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
-               glob_cfg->reent_lvl,
-               glob_cfg->save_addr);
+               glob_cfg->total_x, glob_cfg->total_y);
 
        /* dump extended cfg */
-       cfg = PTR_STI((unsigned long)glob_cfg->ext_ptr);
        pr_debug("monitor %d\n"
                "in friendly mode: %d\n"
                "power consumption %d watts\n"
                "freq ref %d\n"
-               "sti_mem_addr %08x (size=%d bytes)\n",
+               "sti_mem_addr %px (size=%d bytes)\n",
                cfg->curr_mon,
                cfg->friendly_boot,
                cfg->power,
                cfg->freq_ref,
-               cfg->sti_mem_addr, sti_mem_request);
+               cfg->sti_mem_addr, sti->sti_mem_request);
 }
 
 static void sti_dump_outptr(struct sti_struct *sti)
@@ -414,7 +445,7 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,
 {
        struct sti_glob_cfg *glob_cfg;
        struct sti_glob_cfg_ext *glob_cfg_ext;
-       void *save_addr;
+       void *save_addr, *ptr;
        void *sti_mem_addr;
        int i, size;
 
@@ -432,9 +463,7 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,
        save_addr       = &sti->sti_data->save_addr;
        sti_mem_addr    = &sti->sti_data->sti_mem_addr;
 
-       glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
-       glob_cfg->save_addr = STI_PTR(save_addr);
-       for (i=0; i<8; i++) {
+       for (i = 0; i < STI_REGION_MAX; i++) {
                unsigned long newhpa, len;
 
                if (sti->pd) {
@@ -457,13 +486,10 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,
                        REGION_OFFSET_TO_PHYS(sti->regions[i], newhpa);
 
                len = sti->regions[i].region_desc.length * 4096;
-               if (len)
-                       glob_cfg->region_ptrs[i] = sti->regions_phys[i];
 
-               pr_debug("region #%d: phys %08lx, region_ptr %08x, len=%lukB, "
+               pr_debug("region #%d: phys %08lx, len=%lukB, "
                         "btlb=%d, sysonly=%d, cache=%d, last=%d\n",
-                       i, sti->regions_phys[i], glob_cfg->region_ptrs[i],
-                       len/1024,
+                       i, sti->regions_phys[i], len / 1024,
                        sti->regions[i].region_desc.btlb,
                        sti->regions[i].region_desc.sys_only,
                        sti->regions[i].region_desc.cache,
@@ -474,11 +500,16 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address,
                        break;
        }
 
-       if (++i<8 && sti->regions[i].region)
-               pr_warn("future ptr (0x%8x) not yet supported !\n",
-                       sti->regions[i].region);
+       ptr = &glob_cfg->region_ptrs;
+       for (i = 0; i < STI_REGION_MAX; i++)
+               ptr = store_sti_val(sti, ptr, sti->regions_phys[i]);
+
+       *(s32 *)ptr = 0;        /* set reent_lvl */
+       ptr += sizeof(s32);
+       ptr = store_sti_ptr(sti, ptr, save_addr);
+       ptr = store_sti_ptr(sti, ptr, glob_cfg_ext);
 
-       glob_cfg_ext->sti_mem_addr = STI_PTR(sti_mem_addr);
+       store_sti_ptr(sti, &glob_cfg_ext->sti_mem_addr, sti_mem_addr);
 
        sti->glob_cfg = glob_cfg;
 
@@ -802,10 +833,19 @@ static int sti_read_rom(int wordmode, struct sti_struct *sti,
                raw->alt_code_type == ALT_CODE_TYPE_PA_RISC_64
                ? "and 64 " : "");
 
-       sti->font_unpmv = address + (raw->font_unpmv & 0x03ffffff);
-       sti->block_move = address + (raw->block_move & 0x03ffffff);
-       sti->init_graph = address + (raw->init_graph & 0x03ffffff);
-       sti->inq_conf   = address + (raw->inq_conf   & 0x03ffffff);
+       if (IS_ENABLED(CONFIG_64BIT) &&
+           raw->alt_code_type == ALT_CODE_TYPE_PA_RISC_64) {
+               sti->do_call64 = 1;
+               sti->font_unpmv = address + (raw->font_unp_addr   & 0x03ffffff);
+               sti->block_move = address + (raw->block_move_addr & 0x03ffffff);
+               sti->init_graph = address + (raw->init_graph_addr & 0x03ffffff);
+               sti->inq_conf   = address + (raw->inq_conf_addr   & 0x03ffffff);
+       } else {
+               sti->font_unpmv = address + (raw->font_unpmv & 0x03ffffff);
+               sti->block_move = address + (raw->block_move & 0x03ffffff);
+               sti->init_graph = address + (raw->init_graph & 0x03ffffff);
+               sti->inq_conf   = address + (raw->inq_conf   & 0x03ffffff);
+       }
 
        sti->rom = cooked;
        sti->rom->raw = raw;
@@ -818,7 +858,13 @@ static int sti_read_rom(int wordmode, struct sti_struct *sti,
        sti_font_convert_bytemode(sti, sti->font);
        sti_dump_font(sti->font);
 
+       pr_info("    using %d-bit STI ROM functions\n",
+               (IS_ENABLED(CONFIG_64BIT) && sti->do_call64) ? 64 : 32);
+
        sti->sti_mem_request = raw->sti_mem_req;
+       pr_debug("    mem_request = %d,  reentsize %d\n",
+                sti->sti_mem_request, raw->reentsize);
+
        sti->graphics_id[0] = raw->graphics_id[0];
        sti->graphics_id[1] = raw->graphics_id[1];
 
@@ -876,10 +922,12 @@ static struct sti_struct *sti_try_rom_generic(unsigned long address,
        spin_lock_init(&sti->lock);
 
 test_rom:
-       /* if we can't read the ROM, bail out early.  Not being able
-        * to read the hpa is okay, for romless sti */
-       if (pdc_add_valid(address))
+       /* pdc_add_valid() works only on 32-bit kernels */
+       if ((!IS_ENABLED(CONFIG_64BIT) ||
+            (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS32)) &&
+           pdc_add_valid(address)) {
                goto out_err;
+       }
 
        sig = gsc_readl(address);
 
@@ -949,7 +997,7 @@ test_rom:
                goto out_err;
 
        sti_inq_conf(sti);
-       sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request);
+       sti_dump_globcfg(sti);
        sti_dump_outptr(sti);
 
        pr_info("    graphics card name: %s\n",
@@ -1135,14 +1183,15 @@ int sti_call(const struct sti_struct *sti, unsigned long func,
        unsigned long _glob_cfg = STI_PTR(glob_cfg);
        int ret;
 
-#ifdef CONFIG_64BIT
        /* Check for overflow when using 32bit STI on 64bit kernel. */
-       if (WARN_ONCE(_flags>>32 || _inptr>>32 || _outptr>>32 || _glob_cfg>>32,
+       if (WARN_ONCE(IS_ENABLED(CONFIG_64BIT) && !sti->do_call64 &&
+                     (upper_32_bits(_flags) || upper_32_bits(_inptr) ||
+                     upper_32_bits(_outptr) || upper_32_bits(_glob_cfg)),
                        "Out of 32bit-range pointers!"))
                return -1;
-#endif
 
-       ret = pdc_sti_call(func, _flags, _inptr, _outptr, _glob_cfg, 0);
+       ret = pdc_sti_call(func, _flags, _inptr, _outptr, _glob_cfg,
+                          sti->do_call64);
 
        return ret;
 }
index fbb78d7..945ad60 100644 (file)
@@ -39,7 +39,6 @@ struct fb_info;
 #define STI_WAIT 1
 
 #define STI_PTR(p)     ( virt_to_phys(p) )
-#define PTR_STI(p)     ( phys_to_virt((unsigned long)p) )
 
 #define sti_onscreen_x(sti) (sti->glob_cfg->onscreen_x)
 #define sti_onscreen_y(sti) (sti->glob_cfg->onscreen_y)
@@ -78,8 +77,8 @@ struct sti_glob_cfg_ext {
         u8 friendly_boot;              /* in friendly boot mode */
        s16 power;                      /* power calculation (in Watts) */
        s32 freq_ref;                   /* frequency reference */
-       u32 sti_mem_addr;               /* pointer to global sti memory (size=sti_mem_request) */
-       u32 future_ptr;                 /* pointer to future data */
+       u32 *sti_mem_addr;              /* pointer to global sti memory (size=sti_mem_request) */
+       u32 *future_ptr;                /* pointer to future data */
 };
 
 struct sti_glob_cfg {
@@ -90,10 +89,10 @@ struct sti_glob_cfg {
        s16 offscreen_y;                /* offset height in pixels */
        s16 total_x;                    /* frame buffer width in pixels */
        s16 total_y;                    /* frame buffer height in pixels */
-       u32 region_ptrs[STI_REGION_MAX]; /* region pointers */
+       u32 *region_ptrs[STI_REGION_MAX]; /* region pointers */
        s32 reent_lvl;                  /* storage for reentry level value */
-       u32 save_addr;                  /* where to save or restore reentrant state */
-       u32 ext_ptr;                    /* pointer to extended glob_cfg data structure */
+       u32 *save_addr;                 /* where to save or restore reentrant state */
+       u32 *ext_ptr;                   /* pointer to extended glob_cfg data structure */
 };
 
 
@@ -119,26 +118,26 @@ struct sti_init_flags {
        u32 caller_kernel : 1;  /* set only by kernel for each call */
        u32 caller_other : 1;   /* set only by non-[BR/K] caller */
        u32 pad : 14;           /* pad to word boundary */
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 struct sti_init_inptr_ext {
        u8  config_mon_type;    /* configure to monitor type */
        u8  pad[1];             /* pad to word boundary */
        u16 inflight_data;      /* inflight data possible on PCI */
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 struct sti_init_inptr {
        s32 text_planes;        /* number of planes to use for text */
-       u32 ext_ptr;            /* pointer to extended init_graph inptr data structure*/
+       u32 *ext_ptr;           /* pointer to extended init_graph inptr data structure*/
 };
 
 
 struct sti_init_outptr {
        s32 errno;              /* error number on failure */
        s32 text_planes;        /* number of planes used for text */
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 
@@ -148,17 +147,17 @@ struct sti_init_outptr {
 struct sti_conf_flags {
        u32 wait : 1;           /* should routine idle wait or not */
        u32 pad : 31;           /* pad to word boundary */
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 struct sti_conf_inptr {
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 struct sti_conf_outptr_ext {
        u32 crt_config[3];      /* hardware specific X11/OGL information */
        u32 crt_hdw[3];
-       u32 future_ptr;
+       u32 *future_ptr;
 };
 
 struct sti_conf_outptr {
@@ -174,7 +173,7 @@ struct sti_conf_outptr {
        s32 planes;             /* number of fb planes in system */
         u8 dev_name[STI_DEV_NAME_LENGTH]; /* null terminated product name */
        u32 attributes;         /* flags denoting attributes */
-       u32 ext_ptr;            /* pointer to future data */
+       u32 *ext_ptr;           /* pointer to future data */
 };
 
 struct sti_rom {
@@ -258,25 +257,25 @@ struct sti_cooked_rom {
 /* STI font printing function structs */
 
 struct sti_font_inptr {
-       u32 font_start_addr;    /* address of font start */
+       u32 *font_start_addr;   /* address of font start */
        s16 index;              /* index into font table of character */
        u8 fg_color;            /* foreground color of character */
        u8 bg_color;            /* background color of character */
        s16 dest_x;             /* X location of character upper left */
        s16 dest_y;             /* Y location of character upper left */
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 struct sti_font_flags {
        u32 wait : 1;           /* should routine idle wait or not */
        u32 non_text : 1;       /* font unpack/move in non_text planes =1, text =0 */
        u32 pad : 30;           /* pad to word boundary */
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 struct sti_font_outptr {
        s32 errno;              /* error number on failure */
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 /* STI blockmove structs */
@@ -287,7 +286,7 @@ struct sti_blkmv_flags {
        u32 clear : 1;          /* clear during move? */
        u32 non_text : 1;       /* block move in non_text planes =1, text =0 */
        u32 pad : 28;           /* pad to word boundary */
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 struct sti_blkmv_inptr {
@@ -299,12 +298,12 @@ struct sti_blkmv_inptr {
        s16 dest_y;             /* dest upper left pixel y location */
        s16 width;              /* block width in pixels */
        s16 height;             /* block height in pixels */
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 struct sti_blkmv_outptr {
        s32 errno;              /* error number on failure */
-       u32 future_ptr;         /* pointer to future data */
+       u32 *future_ptr;        /* pointer to future data */
 };
 
 
@@ -351,6 +350,7 @@ struct sti_struct {
        unsigned long block_move;
        unsigned long init_graph;
        unsigned long inq_conf;
+       int do_call64;                  /* call 64-bit code */
 
        /* all following fields are initialized by the generic routines */
        int text_planes;