forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
parisc: sticon - unbreak on 64bit kernel
STI text console (sticon) was broken on 64bit machines with more than 4GB RAM and this lead in some cases to a kernel crash. Since sticon uses the 32bit STI API it needs to keep pointers to memory below 4GB. But on a 64bit kernel some memory regions (e.g. the kernel stack) might be above 4GB which then may crash the kernel in the STI functions. Additionally sticon didn't selected the built-in framebuffer fonts by default. This is now fixed. On a side-note: Theoretically we could enhance the sticon driver to use the 64bit STI API. But - beside the fact that some machines don't provide a 64bit STI ROM - this would just add complexity. Signed-off-by: Helge Deller <[email protected]> Cc: [email protected] # 3.8+
- Loading branch information
Showing
3 changed files
with
158 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
* core code for console driver using HP's STI firmware | ||
* | ||
* Copyright (C) 2000 Philipp Rumpf <[email protected]> | ||
* Copyright (C) 2001-2003 Helge Deller <[email protected]> | ||
* Copyright (C) 2001-2013 Helge Deller <[email protected]> | ||
* Copyright (C) 2001-2002 Thomas Bogendoerfer <[email protected]> | ||
* | ||
* TODO: | ||
|
@@ -30,7 +30,7 @@ | |
|
||
#include "../sticore.h" | ||
|
||
#define STI_DRIVERVERSION "Version 0.9a" | ||
#define STI_DRIVERVERSION "Version 0.9b" | ||
|
||
static struct sti_struct *default_sti __read_mostly; | ||
|
||
|
@@ -73,28 +73,34 @@ static const struct sti_init_flags default_init_flags = { | |
|
||
static int sti_init_graph(struct sti_struct *sti) | ||
{ | ||
struct sti_init_inptr_ext inptr_ext = { 0, }; | ||
struct sti_init_inptr inptr = { | ||
.text_planes = 3, /* # of text planes (max 3 for STI) */ | ||
.ext_ptr = STI_PTR(&inptr_ext) | ||
}; | ||
struct sti_init_outptr outptr = { 0, }; | ||
struct sti_init_inptr *inptr = &sti->sti_data->init_inptr; | ||
struct sti_init_inptr_ext *inptr_ext = &sti->sti_data->init_inptr_ext; | ||
struct sti_init_outptr *outptr = &sti->sti_data->init_outptr; | ||
unsigned long flags; | ||
int ret; | ||
int ret, err; | ||
|
||
spin_lock_irqsave(&sti->lock, flags); | ||
|
||
ret = STI_CALL(sti->init_graph, &default_init_flags, &inptr, | ||
&outptr, sti->glob_cfg); | ||
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); | ||
outptr->errno = 0; | ||
|
||
ret = sti_call(sti, sti->init_graph, &default_init_flags, inptr, | ||
outptr, sti->glob_cfg); | ||
|
||
if (ret >= 0) | ||
sti->text_planes = outptr->text_planes; | ||
err = outptr->errno; | ||
|
||
spin_unlock_irqrestore(&sti->lock, flags); | ||
|
||
if (ret < 0) { | ||
printk(KERN_ERR "STI init_graph failed (ret %d, errno %d)\n",ret,outptr.errno); | ||
pr_err("STI init_graph failed (ret %d, errno %d)\n", ret, err); | ||
return -1; | ||
} | ||
|
||
sti->text_planes = outptr.text_planes; | ||
return 0; | ||
} | ||
|
||
|
@@ -104,16 +110,18 @@ static const struct sti_conf_flags default_conf_flags = { | |
|
||
static void sti_inq_conf(struct sti_struct *sti) | ||
{ | ||
struct sti_conf_inptr inptr = { 0, }; | ||
struct sti_conf_inptr *inptr = &sti->sti_data->inq_inptr; | ||
struct sti_conf_outptr *outptr = &sti->sti_data->inq_outptr; | ||
unsigned long flags; | ||
s32 ret; | ||
|
||
sti->outptr.ext_ptr = STI_PTR(&sti->outptr_ext); | ||
outptr->ext_ptr = STI_PTR(&sti->sti_data->inq_outptr_ext); | ||
|
||
do { | ||
spin_lock_irqsave(&sti->lock, flags); | ||
ret = STI_CALL(sti->inq_conf, &default_conf_flags, | ||
&inptr, &sti->outptr, sti->glob_cfg); | ||
memset(inptr, 0, sizeof(*inptr)); | ||
ret = sti_call(sti, sti->inq_conf, &default_conf_flags, | ||
inptr, outptr, sti->glob_cfg); | ||
spin_unlock_irqrestore(&sti->lock, flags); | ||
} while (ret == 1); | ||
} | ||
|
@@ -126,22 +134,24 @@ static const struct sti_font_flags default_font_flags = { | |
void | ||
sti_putc(struct sti_struct *sti, int c, int y, int x) | ||
{ | ||
struct sti_font_inptr inptr = { | ||
struct sti_font_inptr *inptr = &sti->sti_data->font_inptr; | ||
struct sti_font_inptr inptr_default = { | ||
.font_start_addr= STI_PTR(sti->font->raw), | ||
.index = c_index(sti, c), | ||
.fg_color = c_fg(sti, c), | ||
.bg_color = c_bg(sti, c), | ||
.dest_x = x * sti->font_width, | ||
.dest_y = y * sti->font_height, | ||
}; | ||
struct sti_font_outptr outptr = { 0, }; | ||
struct sti_font_outptr *outptr = &sti->sti_data->font_outptr; | ||
s32 ret; | ||
unsigned long flags; | ||
|
||
do { | ||
spin_lock_irqsave(&sti->lock, flags); | ||
ret = STI_CALL(sti->font_unpmv, &default_font_flags, | ||
&inptr, &outptr, sti->glob_cfg); | ||
*inptr = inptr_default; | ||
ret = sti_call(sti, sti->font_unpmv, &default_font_flags, | ||
inptr, outptr, sti->glob_cfg); | ||
spin_unlock_irqrestore(&sti->lock, flags); | ||
} while (ret == 1); | ||
} | ||
|
@@ -156,7 +166,8 @@ void | |
sti_set(struct sti_struct *sti, int src_y, int src_x, | ||
int height, int width, u8 color) | ||
{ | ||
struct sti_blkmv_inptr inptr = { | ||
struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr; | ||
struct sti_blkmv_inptr inptr_default = { | ||
.fg_color = color, | ||
.bg_color = color, | ||
.src_x = src_x, | ||
|
@@ -166,14 +177,15 @@ sti_set(struct sti_struct *sti, int src_y, int src_x, | |
.width = width, | ||
.height = height, | ||
}; | ||
struct sti_blkmv_outptr outptr = { 0, }; | ||
struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr; | ||
s32 ret; | ||
unsigned long flags; | ||
|
||
do { | ||
spin_lock_irqsave(&sti->lock, flags); | ||
ret = STI_CALL(sti->block_move, &clear_blkmv_flags, | ||
&inptr, &outptr, sti->glob_cfg); | ||
*inptr = inptr_default; | ||
ret = sti_call(sti, sti->block_move, &clear_blkmv_flags, | ||
inptr, outptr, sti->glob_cfg); | ||
spin_unlock_irqrestore(&sti->lock, flags); | ||
} while (ret == 1); | ||
} | ||
|
@@ -182,7 +194,8 @@ void | |
sti_clear(struct sti_struct *sti, int src_y, int src_x, | ||
int height, int width, int c) | ||
{ | ||
struct sti_blkmv_inptr inptr = { | ||
struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr; | ||
struct sti_blkmv_inptr inptr_default = { | ||
.fg_color = c_fg(sti, c), | ||
.bg_color = c_bg(sti, c), | ||
.src_x = src_x * sti->font_width, | ||
|
@@ -192,14 +205,15 @@ sti_clear(struct sti_struct *sti, int src_y, int src_x, | |
.width = width * sti->font_width, | ||
.height = height* sti->font_height, | ||
}; | ||
struct sti_blkmv_outptr outptr = { 0, }; | ||
struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr; | ||
s32 ret; | ||
unsigned long flags; | ||
|
||
do { | ||
spin_lock_irqsave(&sti->lock, flags); | ||
ret = STI_CALL(sti->block_move, &clear_blkmv_flags, | ||
&inptr, &outptr, sti->glob_cfg); | ||
*inptr = inptr_default; | ||
ret = sti_call(sti, sti->block_move, &clear_blkmv_flags, | ||
inptr, outptr, sti->glob_cfg); | ||
spin_unlock_irqrestore(&sti->lock, flags); | ||
} while (ret == 1); | ||
} | ||
|
@@ -212,22 +226,24 @@ void | |
sti_bmove(struct sti_struct *sti, int src_y, int src_x, | ||
int dst_y, int dst_x, int height, int width) | ||
{ | ||
struct sti_blkmv_inptr inptr = { | ||
struct sti_blkmv_inptr *inptr = &sti->sti_data->blkmv_inptr; | ||
struct sti_blkmv_inptr inptr_default = { | ||
.src_x = src_x * sti->font_width, | ||
.src_y = src_y * sti->font_height, | ||
.dest_x = dst_x * sti->font_width, | ||
.dest_y = dst_y * sti->font_height, | ||
.width = width * sti->font_width, | ||
.height = height* sti->font_height, | ||
}; | ||
struct sti_blkmv_outptr outptr = { 0, }; | ||
struct sti_blkmv_outptr *outptr = &sti->sti_data->blkmv_outptr; | ||
s32 ret; | ||
unsigned long flags; | ||
|
||
do { | ||
spin_lock_irqsave(&sti->lock, flags); | ||
ret = STI_CALL(sti->block_move, &default_blkmv_flags, | ||
&inptr, &outptr, sti->glob_cfg); | ||
*inptr = inptr_default; | ||
ret = sti_call(sti, sti->block_move, &default_blkmv_flags, | ||
inptr, outptr, sti->glob_cfg); | ||
spin_unlock_irqrestore(&sti->lock, flags); | ||
} while (ret == 1); | ||
} | ||
|
@@ -284,7 +300,7 @@ __setup("sti=", sti_setup); | |
|
||
|
||
|
||
static char *font_name[MAX_STI_ROMS] = { "VGA8x16", }; | ||
static char *font_name[MAX_STI_ROMS]; | ||
static int font_index[MAX_STI_ROMS], | ||
font_height[MAX_STI_ROMS], | ||
font_width[MAX_STI_ROMS]; | ||
|
@@ -389,10 +405,10 @@ static void sti_dump_outptr(struct sti_struct *sti) | |
"%d used bits\n" | ||
"%d planes\n" | ||
"attributes %08x\n", | ||
sti->outptr.bits_per_pixel, | ||
sti->outptr.bits_used, | ||
sti->outptr.planes, | ||
sti->outptr.attributes)); | ||
sti->sti_data->inq_outptr.bits_per_pixel, | ||
sti->sti_data->inq_outptr.bits_used, | ||
sti->sti_data->inq_outptr.planes, | ||
sti->sti_data->inq_outptr.attributes)); | ||
} | ||
|
||
static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address, | ||
|
@@ -402,24 +418,21 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address, | |
struct sti_glob_cfg_ext *glob_cfg_ext; | ||
void *save_addr; | ||
void *sti_mem_addr; | ||
const int save_addr_size = 1024; /* XXX */ | ||
int i; | ||
int i, size; | ||
|
||
if (!sti->sti_mem_request) | ||
if (sti->sti_mem_request < 256) | ||
sti->sti_mem_request = 256; /* STI default */ | ||
|
||
glob_cfg = kzalloc(sizeof(*sti->glob_cfg), GFP_KERNEL); | ||
glob_cfg_ext = kzalloc(sizeof(*glob_cfg_ext), GFP_KERNEL); | ||
save_addr = kzalloc(save_addr_size, GFP_KERNEL); | ||
sti_mem_addr = kzalloc(sti->sti_mem_request, GFP_KERNEL); | ||
size = sizeof(struct sti_all_data) + sti->sti_mem_request - 256; | ||
|
||
if (!(glob_cfg && glob_cfg_ext && save_addr && sti_mem_addr)) { | ||
kfree(glob_cfg); | ||
kfree(glob_cfg_ext); | ||
kfree(save_addr); | ||
kfree(sti_mem_addr); | ||
sti->sti_data = kzalloc(size, STI_LOWMEM); | ||
if (!sti->sti_data) | ||
return -ENOMEM; | ||
} | ||
|
||
glob_cfg = &sti->sti_data->glob_cfg; | ||
glob_cfg_ext = &sti->sti_data->glob_cfg_ext; | ||
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); | ||
|
@@ -475,32 +488,31 @@ static int sti_init_glob_cfg(struct sti_struct *sti, unsigned long rom_address, | |
return 0; | ||
} | ||
|
||
#ifdef CONFIG_FB | ||
#ifdef CONFIG_FONTS | ||
static struct sti_cooked_font * | ||
sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name) | ||
{ | ||
const struct font_desc *fbfont; | ||
const struct font_desc *fbfont = NULL; | ||
unsigned int size, bpc; | ||
void *dest; | ||
struct sti_rom_font *nf; | ||
struct sti_cooked_font *cooked_font; | ||
|
||
if (!fbfont_name || !strlen(fbfont_name)) | ||
return NULL; | ||
fbfont = find_font(fbfont_name); | ||
if (fbfont_name && strlen(fbfont_name)) | ||
fbfont = find_font(fbfont_name); | ||
if (!fbfont) | ||
fbfont = get_default_font(1024,768, ~(u32)0, ~(u32)0); | ||
if (!fbfont) | ||
return NULL; | ||
|
||
DPRINTK((KERN_DEBUG "selected %dx%d fb-font %s\n", | ||
fbfont->width, fbfont->height, fbfont->name)); | ||
pr_info("STI selected %dx%d framebuffer font %s for sticon\n", | ||
fbfont->width, fbfont->height, fbfont->name); | ||
|
||
bpc = ((fbfont->width+7)/8) * fbfont->height; | ||
size = bpc * 256; | ||
size += sizeof(struct sti_rom_font); | ||
|
||
nf = kzalloc(size, GFP_KERNEL); | ||
nf = kzalloc(size, STI_LOWMEM); | ||
if (!nf) | ||
return NULL; | ||
|
||
|
@@ -637,7 +649,7 @@ static void *sti_bmode_font_raw(struct sti_cooked_font *f) | |
unsigned char *n, *p, *q; | ||
int size = f->raw->bytes_per_char*256+sizeof(struct sti_rom_font); | ||
|
||
n = kzalloc (4*size, GFP_KERNEL); | ||
n = kzalloc(4*size, STI_LOWMEM); | ||
if (!n) | ||
return NULL; | ||
p = n + 3; | ||
|
@@ -673,7 +685,7 @@ static struct sti_rom *sti_get_bmode_rom (unsigned long address) | |
sti_bmode_rom_copy(address + BMODE_LAST_ADDR_OFFS, sizeof(size), &size); | ||
|
||
size = (size+3) / 4; | ||
raw = kmalloc(size, GFP_KERNEL); | ||
raw = kmalloc(size, STI_LOWMEM); | ||
if (raw) { | ||
sti_bmode_rom_copy(address, size, raw); | ||
memmove (&raw->res004, &raw->type[0], 0x3c); | ||
|
@@ -707,7 +719,7 @@ static struct sti_rom *sti_get_wmode_rom(unsigned long address) | |
/* read the ROM size directly from the struct in ROM */ | ||
size = gsc_readl(address + offsetof(struct sti_rom,last_addr)); | ||
|
||
raw = kmalloc(size, GFP_KERNEL); | ||
raw = kmalloc(size, STI_LOWMEM); | ||
if (raw) | ||
sti_rom_copy(address, size, raw); | ||
|
||
|
@@ -743,6 +755,10 @@ static int sti_read_rom(int wordmode, struct sti_struct *sti, | |
|
||
address = (unsigned long) STI_PTR(raw); | ||
|
||
pr_info("STI ROM supports 32 %sbit firmware functions.\n", | ||
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); | ||
|
@@ -901,7 +917,8 @@ static struct sti_struct *sti_try_rom_generic(unsigned long address, | |
sti_dump_globcfg(sti->glob_cfg, sti->sti_mem_request); | ||
sti_dump_outptr(sti); | ||
|
||
printk(KERN_INFO " graphics card name: %s\n", sti->outptr.dev_name ); | ||
pr_info(" graphics card name: %s\n", | ||
sti->sti_data->inq_outptr.dev_name); | ||
|
||
sti_roms[num_sti_roms] = sti; | ||
num_sti_roms++; | ||
|
@@ -1073,6 +1090,29 @@ struct sti_struct * sti_get_rom(unsigned int index) | |
} | ||
EXPORT_SYMBOL(sti_get_rom); | ||
|
||
|
||
int sti_call(const struct sti_struct *sti, unsigned long func, | ||
const void *flags, void *inptr, void *outptr, | ||
struct sti_glob_cfg *glob_cfg) | ||
{ | ||
unsigned long _flags = STI_PTR(flags); | ||
unsigned long _inptr = STI_PTR(inptr); | ||
unsigned long _outptr = STI_PTR(outptr); | ||
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, | ||
"Out of 32bit-range pointers!")) | ||
return -1; | ||
#endif | ||
|
||
ret = pdc_sti_call(func, _flags, _inptr, _outptr, _glob_cfg); | ||
|
||
return ret; | ||
} | ||
|
||
MODULE_AUTHOR("Philipp Rumpf, Helge Deller, Thomas Bogendoerfer"); | ||
MODULE_DESCRIPTION("Core STI driver for HP's NGLE series graphics cards in HP PARISC machines"); | ||
MODULE_LICENSE("GPL v2"); | ||
|
Oops, something went wrong.