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 on HP graphic cards like Visualize-FX5/FX10/FXe. When calling 32-bit code from a 64-bit kernel one may need to copy contents on the CPU stack from high memory down below the 4GB limit. Signed-off-by: Helge Deller <deller@xxxxxx> --- v2: Forward-ported to apply cleanly on drm-misc-next git tree diff --git a/arch/parisc/include/asm/pdc.h b/arch/parisc/include/asm/pdc.h index 2b4fad8328e8..269b9a159f01 100644 --- a/arch/parisc/include/asm/pdc.h +++ b/arch/parisc/include/asm/pdc.h @@ -88,8 +88,8 @@ int pdc_iodc_print(const unsigned char *str, unsigned count); void pdc_emergency_unlock(void); int pdc_sti_call(unsigned long func, unsigned long flags, - unsigned long inptr, unsigned long outputr, - unsigned long glob_cfg); + unsigned long inptr, unsigned long outputr, + unsigned long glob_cfg, int do_call64); int __pdc_cpu_rendezvous(void); void pdc_cpu_rendezvous_lock(void); diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index cc124d9f1f7f..71ef1640db5a 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -1389,17 +1389,24 @@ int pdc_iodc_getc(void) } int pdc_sti_call(unsigned long func, unsigned long flags, - unsigned long inptr, unsigned long outputr, - unsigned long glob_cfg) + unsigned long inptr, unsigned long outputr, + unsigned long glob_cfg, int do_call64) { - int retval; + int retval = 0; unsigned long irqflags; - spin_lock_irqsave(&pdc_lock, irqflags); - retval = real32_call(func, flags, inptr, outputr, glob_cfg); - spin_unlock_irqrestore(&pdc_lock, irqflags); + spin_lock_irqsave(&pdc_lock, irqflags); + if (IS_ENABLED(CONFIG_64BIT) && do_call64) { +#ifdef CONFIG_64BIT + retval = real64_call(func, flags, inptr, outputr, glob_cfg); +#else + WARN_ON(1); +#endif + } else + retval = real32_call(func, flags, inptr, outputr, glob_cfg); + spin_unlock_irqrestore(&pdc_lock, irqflags); - return retval; + return retval; } EXPORT_SYMBOL(pdc_sti_call); diff --git a/drivers/video/fbdev/stifb.c b/drivers/video/fbdev/stifb.c index baca6974e288..fe54ca8726e6 100644 --- a/drivers/video/fbdev/stifb.c +++ b/drivers/video/fbdev/stifb.c @@ -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 diff --git a/drivers/video/sticore.c b/drivers/video/sticore.c index 7eb925f2ba9c..7a57dacbb15c 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@xxxxxxx> - * Copyright (C) 2001-2020 Helge Deller <deller@xxxxxx> + * Copyright (C) 2001-2023 Helge Deller <deller@xxxxxx> * Copyright (C) 2001-2002 Thomas Bogendoerfer <tsbogend@xxxxxxxxxxxxxxxx> * * 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) +{ + 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; + } else { + /* used for 32-bit STI ROM */ + u32 *ptr32 = ptr; + + *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 @@ static struct sti_struct *sti_try_rom_generic(unsigned long address, 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", @@ -1141,8 +1189,8 @@ int sti_call(const struct sti_struct *sti, unsigned long func, "Out of 32bit-range pointers!")) return -1; #endif - - ret = pdc_sti_call(func, _flags, _inptr, _outptr, _glob_cfg); + ret = pdc_sti_call(func, _flags, _inptr, _outptr, _glob_cfg, + sti->do_call64); return ret; } diff --git a/include/video/sticore.h b/include/video/sticore.h index fbb78d7e7565..945ad60463a1 100644 --- a/include/video/sticore.h +++ b/include/video/sticore.h @@ -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;