diff options
author | Helge Deller <deller@gmx.de> | 2023-05-10 22:17:27 +0200 |
---|---|---|
committer | Helge Deller <deller@gmx.de> | 2023-06-30 17:14:14 +0200 |
commit | 99ef0c67bc85e2ea547e2c6c9ed29480cd361446 (patch) | |
tree | 06a7dcecafb3926874e8164f86d9f43ea7e166f5 /drivers/video/sticore.c | |
parent | ededd9d27834ad1f300436c1b78e58ad4fcf5dd7 (diff) | |
download | linux-99ef0c67bc85e2ea547e2c6c9ed29480cd361446.tar.gz linux-99ef0c67bc85e2ea547e2c6c9ed29480cd361446.tar.bz2 linux-99ef0c67bc85e2ea547e2c6c9ed29480cd361446.zip |
sticon/parisc: Fix STI console on 64-bit only machines
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>
Diffstat (limited to 'drivers/video/sticore.c')
-rw-r--r-- | drivers/video/sticore.c | 159 |
1 files changed, 104 insertions, 55 deletions
diff --git a/drivers/video/sticore.c b/drivers/video/sticore.c index 60ba3ab5b6cc..c3765ad6eedf 100644 --- a/drivers/video/sticore.c +++ b/drivers/video/sticore.c @@ -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; } |