VGA IO on systems with multiple PCI IO domains
Subsystems (4)
PATCH 1/1 VGA IO on systems with multiple PCI IO domains
Well known problem - the legacy in/out functions do not work on machines that have separate ioport address space for each root level PCI bus. On alpha, we didn't care about this too much until recently: older platforms have the dedicated hose (root bus) #0 with the IO port offset 0 (where the ISA bridge with all legacy stuff resides), and the graphic console used to be supported by firmware only on that hose.
But on modern systems (titan and marvel), the firmware supports vga on *any* bus. Even worse, marvel doesn't have dedicated "legacy" hose at all.
So we have to decode and fix IO port addresses inside our in/out functions, which is awful.
The patch is pretty straightforward - it adds "vga_" prefix to every in/out call in vgacon.c, adds __HAVE_ARCH_IOPORT_REMAP hook and falls back to current in/out stuff if the latter is undefined.
I think it might be useful for other 64-bit architectures as well.
Thanks to Jeff for coding this up and testing on privateer and marvel.
Ivan.
drivers/video/console/vgacon.c +135 -135
@@ -152,13 +152,13 @@ static inline void write_vga(unsigned ch#ifndef SLOW_VGA v1 = reg + (val &0xff00 ); v2 = reg +1 + ((val <<8 ) &0xff00 ); -outw (v1, vga_video_port_reg); -outw (v2, vga_video_port_reg); +vga_outw (v1, vga_video_port_reg); +vga_outw (v2, vga_video_port_reg);#else -outb_p (reg, vga_video_port_reg); -outb_p (val >>8 , vga_video_port_val); -outb_p (reg+1 , vga_video_port_reg); -outb_p (val &0xff , vga_video_port_val); +vga_outb_p (reg, vga_video_port_reg); +vga_outb_p (val >>8 , vga_video_port_val); +vga_outb_p (reg+1 , vga_video_port_reg); +vga_outb_p (val &0xff , vga_video_port_val);#endif spin_unlock_irqrestore (&vga_lock, flags); }
@@ -247,8 +247,8 @@ static const char __init *vgacon_startup*/ vga_vram_base =0xa0000 ; vga_vram_end =0xb0000 ; -outb_p (6 ,0x3ce ) ; -outb_p (6 ,0x3cf ) ; +vga_outb_p (6 ,0x3ce ) ; +vga_outb_p (6 ,0x3cf ) ;#endif /*
@@ -258,20 +258,20 @@ static const char __init *vgacon_startup*/ for (i=0 ; i<16 ; i++) { -inb_p (0x3da ) ; -outb_p (i,0x3c0 ) ; -outb_p (i,0x3c0 ) ; +vga_inb_p (0x3da ) ; +vga_outb_p (i,0x3c0 ) ; +vga_outb_p (i,0x3c0 ) ; } -outb_p (0x20 ,0x3c0 ) ; +vga_outb_p (0x20 ,0x3c0 ) ;/* now set the DAC registers back to their * default values */ for (i=0 ; i<16 ; i++) { -outb_p (color_table[i],0x3c8 ) ; -outb_p (default_red[i],0x3c9 ) ; -outb_p (default_grn[i],0x3c9 ) ; -outb_p (default_blu[i],0x3c9 ) ; +vga_outb_p (color_table[i],0x3c8 ) ; +vga_outb_p (default_red[i],0x3c9 ) ; +vga_outb_p (default_grn[i],0x3c9 ) ; +vga_outb_p (default_blu[i],0x3c9 ) ; } } }
@@ -417,18 +417,18 @@ static void vgacon_set_cursor_size(int x lastfrom = from; lastto = to;spin_lock_irqsave (&vga_lock, flags); -outb_p (0x0a , vga_video_port_reg);/* Cursor start */ - curs =inb_p (vga_video_port_val); -outb_p (0x0b , vga_video_port_reg);/* Cursor end */ - cure =inb_p (vga_video_port_val); +vga_outb_p (0x0a , vga_video_port_reg);/* Cursor start */ + curs =vga_inb_p (vga_video_port_val); +vga_outb_p (0x0b , vga_video_port_reg);/* Cursor end */ + cure =vga_inb_p (vga_video_port_val); curs = (curs &0xc0 ) | from; cure = (cure &0xe0 ) | to; -outb_p (0x0a , vga_video_port_reg);/* Cursor start */ -outb_p (curs, vga_video_port_val); -outb_p (0x0b , vga_video_port_reg);/* Cursor end */ -outb_p (cure, vga_video_port_val); +vga_outb_p (0x0a , vga_video_port_reg);/* Cursor start */ +vga_outb_p (curs, vga_video_port_val); +vga_outb_p (0x0b , vga_video_port_reg);/* Cursor end */ +vga_outb_p (cure, vga_video_port_val);spin_unlock_irqrestore (&vga_lock, flags); }
@@ -495,10 +495,10 @@ static void vga_set_palette(struct vc_daint i, j ;for (i=j=0 ; i<16 ; i++) { -outb_p (table[i], dac_reg) ; -outb_p (c->vc_palette[j++]>>2 , dac_val) ; -outb_p (c->vc_palette[j++]>>2 , dac_val) ; -outb_p (c->vc_palette[j++]>>2 , dac_val) ; +vga_outb_p (table[i], dac_reg) ; +vga_outb_p (c->vc_palette[j++]>>2 , dac_val) ; +vga_outb_p (c->vc_palette[j++]>>2 , dac_val) ; +vga_outb_p (c->vc_palette[j++]>>2 , dac_val) ; } }
@@ -535,40 +535,40 @@ static void vga_vesa_blank(int mode)/* save original values of VGA controller registers */ if (!vga_vesa_blanked) {spin_lock_irq (&vga_lock); - vga_state.SeqCtrlIndex =inb_p (seq_port_reg); - vga_state.CrtCtrlIndex =inb_p (vga_video_port_reg); - vga_state.CrtMiscIO =inb_p (video_misc_rd); + vga_state.SeqCtrlIndex =vga_inb_p (seq_port_reg); + vga_state.CrtCtrlIndex =vga_inb_p (vga_video_port_reg); + vga_state.CrtMiscIO =vga_inb_p (video_misc_rd);spin_unlock_irq (&vga_lock); -outb_p (0x00 ,vga_video_port_reg);/* HorizontalTotal */ - vga_state.HorizontalTotal =inb_p (vga_video_port_val); -outb_p (0x01 ,vga_video_port_reg);/* HorizDisplayEnd */ - vga_state.HorizDisplayEnd =inb_p (vga_video_port_val); -outb_p (0x04 ,vga_video_port_reg);/* StartHorizRetrace */ - vga_state.StartHorizRetrace =inb_p (vga_video_port_val); -outb_p (0x05 ,vga_video_port_reg);/* EndHorizRetrace */ - vga_state.EndHorizRetrace =inb_p (vga_video_port_val); -outb_p (0x07 ,vga_video_port_reg);/* Overflow */ - vga_state.Overflow =inb_p (vga_video_port_val); -outb_p (0x10 ,vga_video_port_reg);/* StartVertRetrace */ - vga_state.StartVertRetrace =inb_p (vga_video_port_val); -outb_p (0x11 ,vga_video_port_reg);/* EndVertRetrace */ - vga_state.EndVertRetrace =inb_p (vga_video_port_val); -outb_p (0x17 ,vga_video_port_reg);/* ModeControl */ - vga_state.ModeControl =inb_p (vga_video_port_val); -outb_p (0x01 ,seq_port_reg);/* ClockingMode */ - vga_state.ClockingMode =inb_p (seq_port_val); +vga_outb_p (0x00 ,vga_video_port_reg);/* HorizontalTotal */ + vga_state.HorizontalTotal =vga_inb_p (vga_video_port_val); +vga_outb_p (0x01 ,vga_video_port_reg);/* HorizDisplayEnd */ + vga_state.HorizDisplayEnd =vga_inb_p (vga_video_port_val); +vga_outb_p (0x04 ,vga_video_port_reg);/* StartHorizRetrace */ + vga_state.StartHorizRetrace =vga_inb_p (vga_video_port_val); +vga_outb_p (0x05 ,vga_video_port_reg);/* EndHorizRetrace */ + vga_state.EndHorizRetrace =vga_inb_p (vga_video_port_val); +vga_outb_p (0x07 ,vga_video_port_reg);/* Overflow */ + vga_state.Overflow =vga_inb_p (vga_video_port_val); +vga_outb_p (0x10 ,vga_video_port_reg);/* StartVertRetrace */ + vga_state.StartVertRetrace =vga_inb_p (vga_video_port_val); +vga_outb_p (0x11 ,vga_video_port_reg);/* EndVertRetrace */ + vga_state.EndVertRetrace =vga_inb_p (vga_video_port_val); +vga_outb_p (0x17 ,vga_video_port_reg);/* ModeControl */ + vga_state.ModeControl =vga_inb_p (vga_video_port_val); +vga_outb_p (0x01 ,seq_port_reg);/* ClockingMode */ + vga_state.ClockingMode =vga_inb_p (seq_port_val); }/* assure that video is enabled */ /* "0x20" is VIDEO_ENABLE_bit in register 01 of sequencer */ spin_lock_irq (&vga_lock); -outb_p (0x01 ,seq_port_reg); -outb_p (vga_state.ClockingMode |0x20 ,seq_port_val); +vga_outb_p (0x01 ,seq_port_reg); +vga_outb_p (vga_state.ClockingMode |0x20 ,seq_port_val);/* test for vertical retrace in process.... */ if ((vga_state.CrtMiscIO &0x80 ) ==0x80 ) -outb_p (vga_state.CrtMiscIO &0xef ,video_misc_wr); +vga_outb_p (vga_state.CrtMiscIO &0xef ,video_misc_wr);/* * Set <End of vertical retrace> to minimum (0) and
@@ -576,12 +576,12 @@ static void vga_vesa_blank(int mode)* Result: turn off vertical sync (VSync) pulse. */ if (mode &VESA_VSYNC_SUSPEND ) { -outb_p (0x10 ,vga_video_port_reg);/* StartVertRetrace */ -outb_p (0xff ,vga_video_port_val);/* maximum value */ -outb_p (0x11 ,vga_video_port_reg);/* EndVertRetrace */ -outb_p (0x40 ,vga_video_port_val);/* minimum (bits 0..3) */ -outb_p (0x07 ,vga_video_port_reg);/* Overflow */ -outb_p (vga_state.Overflow |0x84 ,vga_video_port_val);/* bits 9,10 of vert. retrace */ +vga_outb_p (0x10 ,vga_video_port_reg);/* StartVertRetrace */ +vga_outb_p (0xff ,vga_video_port_val);/* maximum value */ +vga_outb_p (0x11 ,vga_video_port_reg);/* EndVertRetrace */ +vga_outb_p (0x40 ,vga_video_port_val);/* minimum (bits 0..3) */ +vga_outb_p (0x07 ,vga_video_port_reg);/* Overflow */ +vga_outb_p (vga_state.Overflow |0x84 ,vga_video_port_val);/* bits 9,10 of vert. retrace */ }if (mode &VESA_HSYNC_SUSPEND ) {
@@ -590,15 +590,15 @@ static void vga_vesa_blank(int mode)* <Start of horizontal Retrace> to maximum * Result: turn off horizontal sync (HSync) pulse. */ -outb_p (0x04 ,vga_video_port_reg);/* StartHorizRetrace */ -outb_p (0xff ,vga_video_port_val);/* maximum */ -outb_p (0x05 ,vga_video_port_reg);/* EndHorizRetrace */ -outb_p (0x00 ,vga_video_port_val);/* minimum (0) */ +vga_outb_p (0x04 ,vga_video_port_reg);/* StartHorizRetrace */ +vga_outb_p (0xff ,vga_video_port_val);/* maximum */ +vga_outb_p (0x05 ,vga_video_port_reg);/* EndHorizRetrace */ +vga_outb_p (0x00 ,vga_video_port_val);/* minimum (0) */ }/* restore both index registers */ -outb_p (vga_state.SeqCtrlIndex,seq_port_reg); -outb_p (vga_state.CrtCtrlIndex,vga_video_port_reg); +vga_outb_p (vga_state.SeqCtrlIndex,seq_port_reg); +vga_outb_p (vga_state.CrtCtrlIndex,vga_video_port_reg);spin_unlock_irq (&vga_lock); }
@@ -606,30 +606,30 @@ static void vga_vesa_unblank(void) {/* restore original values of VGA controller registers */ spin_lock_irq (&vga_lock); -outb_p (vga_state.CrtMiscIO,video_misc_wr); +vga_outb_p (vga_state.CrtMiscIO,video_misc_wr); -outb_p (0x00 ,vga_video_port_reg);/* HorizontalTotal */ -outb_p (vga_state.HorizontalTotal,vga_video_port_val); -outb_p (0x01 ,vga_video_port_reg);/* HorizDisplayEnd */ -outb_p (vga_state.HorizDisplayEnd,vga_video_port_val); -outb_p (0x04 ,vga_video_port_reg);/* StartHorizRetrace */ -outb_p (vga_state.StartHorizRetrace,vga_video_port_val); -outb_p (0x05 ,vga_video_port_reg);/* EndHorizRetrace */ -outb_p (vga_state.EndHorizRetrace,vga_video_port_val); -outb_p (0x07 ,vga_video_port_reg);/* Overflow */ -outb_p (vga_state.Overflow,vga_video_port_val); -outb_p (0x10 ,vga_video_port_reg);/* StartVertRetrace */ -outb_p (vga_state.StartVertRetrace,vga_video_port_val); -outb_p (0x11 ,vga_video_port_reg);/* EndVertRetrace */ -outb_p (vga_state.EndVertRetrace,vga_video_port_val); -outb_p (0x17 ,vga_video_port_reg);/* ModeControl */ -outb_p (vga_state.ModeControl,vga_video_port_val); -outb_p (0x01 ,seq_port_reg);/* ClockingMode */ -outb_p (vga_state.ClockingMode,seq_port_val); +vga_outb_p (0x00 ,vga_video_port_reg);/* HorizontalTotal */ +vga_outb_p (vga_state.HorizontalTotal,vga_video_port_val); +vga_outb_p (0x01 ,vga_video_port_reg);/* HorizDisplayEnd */ +vga_outb_p (vga_state.HorizDisplayEnd,vga_video_port_val); +vga_outb_p (0x04 ,vga_video_port_reg);/* StartHorizRetrace */ +vga_outb_p (vga_state.StartHorizRetrace,vga_video_port_val); +vga_outb_p (0x05 ,vga_video_port_reg);/* EndHorizRetrace */ +vga_outb_p (vga_state.EndHorizRetrace,vga_video_port_val); +vga_outb_p (0x07 ,vga_video_port_reg);/* Overflow */ +vga_outb_p (vga_state.Overflow,vga_video_port_val); +vga_outb_p (0x10 ,vga_video_port_reg);/* StartVertRetrace */ +vga_outb_p (vga_state.StartVertRetrace,vga_video_port_val); +vga_outb_p (0x11 ,vga_video_port_reg);/* EndVertRetrace */ +vga_outb_p (vga_state.EndVertRetrace,vga_video_port_val); +vga_outb_p (0x17 ,vga_video_port_reg);/* ModeControl */ +vga_outb_p (vga_state.ModeControl,vga_video_port_val); +vga_outb_p (0x01 ,seq_port_reg);/* ClockingMode */ +vga_outb_p (vga_state.ClockingMode,seq_port_val);/* restore index/control registers */ -outb_p (vga_state.SeqCtrlIndex,seq_port_reg); -outb_p (vga_state.CrtCtrlIndex,vga_video_port_reg); +vga_outb_p (vga_state.SeqCtrlIndex,seq_port_reg); +vga_outb_p (vga_state.CrtCtrlIndex,vga_video_port_reg);spin_unlock_irq (&vga_lock); }
@@ -638,10 +638,10 @@ static void vga_pal_blank(void)int i;for (i=0 ; i<16 ; i++) { -outb_p (i, dac_reg) ; -outb_p (0 , dac_val) ; -outb_p (0 , dac_val) ; -outb_p (0 , dac_val) ; +vga_outb_p (i, dac_reg) ; +vga_outb_p (0 , dac_val) ; +vga_outb_p (0 , dac_val) ; +vga_outb_p (0 , dac_val) ; } }
@@ -752,21 +752,21 @@ vgacon_do_font_op(char *arg, int set, in#endif spin_lock_irq (&vga_lock); -outb_p (0x00 , seq_port_reg );/* First, the sequencer */ -outb_p (0x01 , seq_port_val );/* Synchronous reset */ -outb_p (0x02 , seq_port_reg ); -outb_p (0x04 , seq_port_val );/* CPU writes only to map 2 */ -outb_p (0x04 , seq_port_reg ); -outb_p (0x07 , seq_port_val );/* Sequential addressing */ -outb_p (0x00 , seq_port_reg ); -outb_p (0x03 , seq_port_val );/* Clear synchronous reset */ - -outb_p (0x04 , gr_port_reg );/* Now, the graphics controller */ -outb_p (0x02 , gr_port_val );/* select map 2 */ -outb_p (0x05 , gr_port_reg ); -outb_p (0x00 , gr_port_val );/* disable odd-even addressing */ -outb_p (0x06 , gr_port_reg ); -outb_p (0x00 , gr_port_val );/* map start at A000:0000 */ +vga_outb_p (0x00 , seq_port_reg );/* First, the sequencer */ +vga_outb_p (0x01 , seq_port_val );/* Synchronous reset */ +vga_outb_p (0x02 , seq_port_reg ); +vga_outb_p (0x04 , seq_port_val );/* CPU writes only to map 2 */ +vga_outb_p (0x04 , seq_port_reg ); +vga_outb_p (0x07 , seq_port_val );/* Sequential addressing */ +vga_outb_p (0x00 , seq_port_reg ); +vga_outb_p (0x03 , seq_port_val );/* Clear synchronous reset */ + +vga_outb_p (0x04 , gr_port_reg );/* Now, the graphics controller */ +vga_outb_p (0x02 , gr_port_val );/* select map 2 */ +vga_outb_p (0x05 , gr_port_reg ); +vga_outb_p (0x00 , gr_port_val );/* disable odd-even addressing */ +vga_outb_p (0x06 , gr_port_reg ); +vga_outb_p (0x00 , gr_port_val );/* map start at A000:0000 */ spin_unlock_irq (&vga_lock);if (arg) {
@@ -795,25 +795,25 @@ vgacon_do_font_op(char *arg, int set, in }spin_lock_irq (&vga_lock); -outb_p (0x00 , seq_port_reg );/* First, the sequencer */ -outb_p (0x01 , seq_port_val );/* Synchronous reset */ -outb_p (0x02 , seq_port_reg ); -outb_p (0x03 , seq_port_val );/* CPU writes to maps 0 and 1 */ -outb_p (0x04 , seq_port_reg ); -outb_p (0x03 , seq_port_val );/* odd-even addressing */ +vga_outb_p (0x00 , seq_port_reg );/* First, the sequencer */ +vga_outb_p (0x01 , seq_port_val );/* Synchronous reset */ +vga_outb_p (0x02 , seq_port_reg ); +vga_outb_p (0x03 , seq_port_val );/* CPU writes to maps 0 and 1 */ +vga_outb_p (0x04 , seq_port_reg ); +vga_outb_p (0x03 , seq_port_val );/* odd-even addressing */ if (set) { -outb_p (0x03 , seq_port_reg );/* Character Map Select */ -outb_p ( font_select, seq_port_val ); +vga_outb_p (0x03 , seq_port_reg );/* Character Map Select */ +vga_outb_p ( font_select, seq_port_val ); } -outb_p (0x00 , seq_port_reg ); -outb_p (0x03 , seq_port_val );/* clear synchronous reset */ +vga_outb_p (0x00 , seq_port_reg ); +vga_outb_p (0x03 , seq_port_val );/* clear synchronous reset */ -outb_p (0x04 , gr_port_reg );/* Now, the graphics controller */ -outb_p (0x00 , gr_port_val );/* select map 0 for CPU */ -outb_p (0x05 , gr_port_reg ); -outb_p (0x10 , gr_port_val );/* enable even-odd addressing */ -outb_p (0x06 , gr_port_reg ); -outb_p ( beg, gr_port_val );/* map starts at b800:0 or b000:0 */ +vga_outb_p (0x04 , gr_port_reg );/* Now, the graphics controller */ +vga_outb_p (0x00 , gr_port_val );/* select map 0 for CPU */ +vga_outb_p (0x05 , gr_port_reg ); +vga_outb_p (0x10 , gr_port_val );/* enable even-odd addressing */ +vga_outb_p (0x06 , gr_port_reg ); +vga_outb_p ( beg, gr_port_val );/* map starts at b800:0 or b000:0 */ /* if 512 char mode is already enabled don't re-enable it. */ if ((set)&&(ch512!=vga_512_chars)) {/* attribute controller */
@@ -826,13 +826,13 @@ vgacon_do_font_op(char *arg, int set, in vga_512_chars=ch512;/* 256-char: enable intensity bit 512-char: disable intensity bit */ -inb_p ( video_port_status );/* clear address flip-flop */ -outb_p (0x12 , attrib_port );/* color plane enable register */ -outb_p ( ch512 ?0x07 :0x0f , attrib_port ); +vga_inb_p ( video_port_status );/* clear address flip-flop */ +vga_outb_p (0x12 , attrib_port );/* color plane enable register */ +vga_outb_p ( ch512 ?0x07 :0x0f , attrib_port );/* Wilton (1987) mentions the following; I don't know what it means, but it works, and it appears necessary */ -inb_p ( video_port_status ); -outb_p (0x20 , attrib_port ); +vga_inb_p ( video_port_status ); +vga_outb_p (0x20 , attrib_port ); }spin_unlock_irq (&vga_lock);return 0 ;
@@ -866,10 +866,10 @@ vgacon_adjust_height(unsigned fontheightare all don't care bits on EGA, so I guess it doesn't matter. */ spin_lock_irq (&vga_lock); -outb_p (0x07 , vga_video_port_reg );/* CRTC overflow register */ - ovr =inb_p (vga_video_port_val); -outb_p (0x09 , vga_video_port_reg );/* Font size register */ - fsr =inb_p (vga_video_port_val); +vga_outb_p (0x07 , vga_video_port_reg );/* CRTC overflow register */ + ovr =vga_inb_p (vga_video_port_val); +vga_outb_p (0x09 , vga_video_port_reg );/* Font size register */ + fsr =vga_inb_p (vga_video_port_val);spin_unlock_irq (&vga_lock); vde = maxscan &0xff ;/* Vertical display end reg */
@@ -879,12 +879,12 @@ vgacon_adjust_height(unsigned fontheight fsr = (fsr &0xe0 ) + (fontheight-1 );/* Font size register */ spin_lock_irq (&vga_lock); -outb_p (0x07 , vga_video_port_reg );/* CRTC overflow register */ -outb_p ( ovr, vga_video_port_val ); -outb_p (0x09 , vga_video_port_reg );/* Font size */ -outb_p ( fsr, vga_video_port_val ); -outb_p (0x12 , vga_video_port_reg );/* Vertical display limit */ -outb_p ( vde, vga_video_port_val ); +vga_outb_p (0x07 , vga_video_port_reg );/* CRTC overflow register */ +vga_outb_p ( ovr, vga_video_port_val ); +vga_outb_p (0x09 , vga_video_port_reg );/* Font size */ +vga_outb_p ( fsr, vga_video_port_val ); +vga_outb_p (0x12 , vga_video_port_reg );/* Vertical display limit */ +vga_outb_p ( vde, vga_video_port_val );spin_unlock_irq (&vga_lock);for (i =0 ; i <MAX_NR_CONSOLES ; i++) {
include/linux/vt_buffer.h +5 -0
@@ -17,6 +17,11 @@#if defined(CONFIG_VGA_CONSOLE ) || defined(CONFIG_MDA_CONSOLE )#include <asm/vga.h> +#ifndef __HAVE_ARCH_IOPORT_REMAP +#define vga_outb_p outb_p +#define vga_outw outw +#define vga_inb_p inb_p +#endif #endif #ifndef VT_BUF_HAVE_RW
Hi!
Quoted 6 lines
But on modern systems (titan and marvel), the firmware supports vga on *any* bus. Even worse, marvel doesn't have dedicated "legacy" hose at all.
So we have to decode and fix IO port addresses inside our in/out functions, which is awful.
Is the problem really only with VGA? Shouldn't we introduce isa_(in|out)(b|w) instead and remap the whole legacy I/O space?
Have a nice fortnight
Signature · 3 lines
Martin `MJ' Mares <[email protected]> http://atrey.karlin.mff.cuni.cz/~mj/ Faculty of Math and Physics, Charles University, Prague, Czech Rep., Earth Don't take life too seriously -- you'll never get out of it alive.
Quoted 11 lines · Martin Mares
Hi!
Quoted 6 lines
But on modern systems (titan and marvel), the firmware supports vga on *any* bus. Even worse, marvel doesn't have dedicated "legacy" hose at all.
So we have to decode and fix IO port addresses inside our in/out functions, which is awful.
Is the problem really only with VGA? Shouldn't we introduce isa_(in|out)(b|w) instead and remap the whole legacy I/O space?
Each time we discussed this, we came to the conclusion that indeed, separate macros for ISA would be useful, but not enough.
We probably need to introduce an equivalent of ioremap for IO space. So far, what we have to deal is:
- Legacy ISA stuff unrelated to a PCI bus
- Legacy devies on a given PCI segment (VGA, serial, IDE, ...)
What about some kind of ioport_remap() that would take a pci_bus and an port range as arguments ? If pci_bus is NULL, that would match a "legacy" ISA bus (non-PCI machine or default ISA bus for machines where that makes sense).
What do you think ?
Ben.
Quoted 6 lines
What about some kind of
ioport_remap()that would take apci_busand an port range as arguments ? Ifpci_busis NULL, that would match a "legacy" ISA bus (non-PCI machine or default ISA bus for machines where that makes sense).What do you think ?
Looks good, but maybe we should use some other functions than iob() et al. to do I/O on the remapped addresses.
Have a nice fortnight
Signature · 3 lines
Martin `MJ' Mares <[email protected]> http://atrey.karlin.mff.cuni.cz/~mj/ Faculty of Math and Physics, Charles University, Prague, Czech Rep., Earth Never make any mistaeks.
Quoted 9 lines · Martin Mares
Quoted 6 lines
What about some kind of
ioport_remap()that would take apci_busand an port range as arguments ? Ifpci_busis NULL, that would match a "legacy" ISA bus (non-PCI machine or default ISA bus for machines where that makes sense).What do you think ?
Looks good, but maybe we should use some other functions than
iob()et al. to do I/O on the remapped addresses.
What about this (what we'd have on alpha):
intlegacy_ioport_remap(struct resource *res)
{
switch (res->start) {
case 0x3c0: /* VGA */
res->start += pci_vga_hose->io_space->start;
res->end += pci_vga_hose->io_space->start;
case ???
...
default:
return -ENODEV;
}
return request_resource(pci_vga_hose->io_space, res);
}voidlegacy_ioport_unmap(struct resource *res)
{
release_resource(res);
}Then vgacon.c would be changed like this:
...
- request_resource(&ioport_resource, &vga_console_resource);
+ if (legacy_ioport_remap(&vga_console_resource) < 0)
+ goto failure;
...
And all in/out port calls would use respective resource.start+offset:
...
- outb_p(6, 0x3ce)
+ outb_p(6, vga_console_resource.start + 0xe);
No need for other special IO functions then.
Ivan.
Quoted 13 lines · Ivan Kokshaysky
Then
vgacon.cwould be changed like this:...
(quoted diff) +2
-1- request_resource(&ioport_resource, &vga_console_resource); + if (legacy_ioport_remap(&vga_console_resource) < 0) + goto failure;And all in/out port calls would use respective resource.start+offset:
...(quoted diff) +1
-1- outb_p(6, 0x3ce) + outb_p(6, vga_console_resource.start + 0xe);
Quoted 1 line
No need for other special IO functions then.
Well, your example clearly limits us to one IO space for VGA, which might not be what we want. The problem also exist for some fbdev drivers which might need to tap the VGA IOs of a given PCI card (thus getting access to the "legacy" IOs of the bus the card is on).
It would be nice to provide some more generic solution to deal with that "ISA" problem...
Finally, in the embedded world, we frequently have to deal with "legacy" controllers (ethernet, serial, ...) stuffed on whatever bus we have around, at addresses that might not be usual port addresses.
It's definitely a good idea to always add a "base" to the legacy IOs as your examples shows though. The problem remaining is how to actually obtain this address for the various cases whe are interested in.
Ben.
Quoted 4 lines · Benjamin Herrenschmidt
Well, your example clearly limits us to one IO space for VGA, which might not be what we want. The problem also exist for some fbdev drivers which might need to tap the VGA IOs of a given PCI card (thus getting access to the "legacy" IOs of the bus the card is on).
You are right, I've already realized that. :-)
The struct pci_bus * arg to legacy_ioport_remap (maybe better pci_legacy_ioport_remap) is really good idea, and it's perfectly ok to pass NULL in the vgacon case - we are limited to only one VGA console anyway.
After the PCI setup is done, pci_legacy_ioport_remap(pbus, &legacy_resource) would solve any problem I can think of, including multiple ISA bridges.
Ivan.
Quoted 6 lines · Ivan Kokshaysky
Quoted 4 lines · Benjamin Herrenschmidt
Well, your example clearly limits us to one IO space for VGA, which might not be what we want. The problem also exist for some fbdev drivers which might need to tap the VGA IOs of a given PCI card (thus getting access to the "legacy" IOs of the bus the card is on).
Quoted 7 lines
You are right, I've already realized that. :-)
The structpci_bus* arg tolegacy_ioport_remap(maybe betterpci_legacy_ioport_remap) is really good idea, and it's perfectly ok to pass NULL in the vgacon case - we are limited to only one VGA console anyway.
After the PCI setup is done,pci_legacy_ioport_remap(pbus, &legacy_resource)would solve any problem I can think of, including multiple ISA bridges.
BTW, we still need a separate isa_request_mem_region(), since right now we cannot simply call request_mem_region(0xa0000, 0x10000) to request the VGA memory buffer in ISA memory space. On ia32 the plain request_mem_region() is OK, but on other archs you need to add the ISA memory space base.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]
In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
Quoted 4 lines · Geert Uytterhoeven
BTW, we still need a separate
isa_request_mem_region(), since right now we cannot simply callrequest_mem_region(0xa0000, 0x10000)to request the VGA memory buffer in ISA memory space. On ia32 the plainrequest_mem_region()is OK, but on other archs you need to add the ISA memory space base.
I agree. Currently the VGA_MAP_MEM() hack does the trick in the vgacon.c, but it would be a lot better to have a generic function. However, I don't think that "isa_" prefix is good - as Ben pointed out, legacy IO ranges of PCI devices like VGA, IDE, serial etc. can be in other IO spaces than the real ISA bus.
What about
int pci_request_legacy_resource(struct pci_bus *bus, struct resource *res) which would check res->flags and make appropriate decision?
The default in <linux/pci.h> for architectures like ia32 will be #ifndef __HAVE_ARCH_LEGACY_REMAP
static inline intpci_request_legacy_resource(struct pci_bus *bus, struct resource *res)
{
struct resource *root = res->flags & IORESOURCE_IO ?
&ioport_resource : &iomem_resource;
return request_resource(root, res);
}#infdef
This can be overridden in <asm/pci.h>.
Ivan.
Quoted 20 lines · Ivan Kokshaysky
Quoted 4 lines · Geert Uytterhoeven
BTW, we still need a separate
isa_request_mem_region(), since right now we cannot simply callrequest_mem_region(0xa0000, 0x10000)to request the VGA memory buffer in ISA memory space. On ia32 the plainrequest_mem_region()is OK, but on other archs you need to add the ISA memory space base.I agree. Currently the
VGA_MAP_MEM()hack does the trick in thevgacon.c, but it would be a lot better to have a generic function. However, I don't think that "isa_" prefix is good - as Ben pointed out, legacy IO ranges of PCI devices like VGA, IDE, serial etc. can be in other IO spaces than the real ISA bus.What about
intpci_request_legacy_resource(struct pci_bus *bus, struct resource *res)which would checkres->flagsand make appropriate decision?The default in <
linux/pci.h> for architectures like ia32 will be #ifndef__HAVE_ARCH_LEGACY_REMAP
static inline intpci_request_legacy_resource(struct pci_bus *bus, struct resource *res)
Quoted 6 lines
{ struct resource *root = res->flags & IORESOURCE_IO ? &ioport_resource : &iomem_resource; return request_resource(root, res); }#infdef
That's OK for me.
Quoted 1 line
This can be overridden in <
asm/pci.h>.
Although legacy resources exist on non-PCI as well.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]
In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
Quoted 3 lines · Geert Uytterhoeven
Quoted 1 line
This can be overridden in <
asm/pci.h>.Although legacy resources exist on non-PCI as well.
Sure, but it's ok to include <linux/pci.h> and use stub PCI interfaces even if CONFIG_PCI is not set.
Ivan.
Here's the patch that converts vgacon.c to pci_request_legacy_resource(). Tested on i386 and a single-bus alpha (alpha specific bits not included here).
Note that it breaks ppc, as VGA_MAP_MEM() is removed...
Ivan.
drivers/video/console/vgacon.c +64 -44
@@ -47,8 +47,8 @@#include <linux/vt_kern.h> #include <linux/selection.h> #include <linux/spinlock.h> -#include <linux/ioport.h> #include <linux/init.h> +#include <linux/pci.h> #include <asm/io.h>
@@ -66,15 +66,15 @@ static spinlock_t vga_lock = SPIN_LOCK_U*/ #undef TRIDENT_GLITCH -#define dac_reg 0x3c8 -#define dac_val 0x3c9 -#define attrib_port 0x3c0 -#define seq_port_reg 0x3c4 -#define seq_port_val 0x3c5 -#define gr_port_reg 0x3ce -#define gr_port_val 0x3cf -#define video_misc_rd 0x3cc -#define video_misc_wr 0x3c2 +#define dac_reg (console_resource->start + 0x8) +#define dac_val (console_resource->start + 0x9) +#define attrib_port (console_resource->start + 0x0) +#define seq_port_reg (console_resource->start + 0x4) +#define seq_port_val (console_resource->start + 0x5) +#define gr_port_reg (console_resource->start + 0xe) +#define gr_port_val (console_resource->start + 0xf) +#define video_misc_rd (console_resource->start + 0xc) +#define video_misc_wr (console_resource->start + 0x2)/* * Interface used by the world
@@ -100,8 +100,8 @@ static unsigned long vgacon_uni_pagedir[/* Description of the hardware situation */ static unsigned long vga_vram_base;/* Base of video memory */ static unsigned long vga_vram_end;/* End of video memory */ -static u16 vga_video_port_reg;/* Video register select port */ -static u16 vga_video_port_val;/* Video register value port */ +static unsigned long vga_video_port_reg;/* Video register select port */ +static unsigned long vga_video_port_val;/* Video register value port */ static unsigned int vga_video_num_columns;/* Number of text columns */ static unsigned int vga_video_num_lines;/* Number of text lines */ static int vga_can_do_color =0 ;/* Do we support colors? */
@@ -116,6 +116,7 @@ static int vga_is_gfx;static int vga_512_chars;static int vga_video_font_height;static unsigned int vga_rolled_over =0 ; +static struct resource *console_resource;static int __init no_scroll (char *str)
@@ -166,6 +167,9 @@ static inline void write_vga(unsigned chstatic const char __init *vgacon_startup (void ) {const char *display_desc =NULL ; +static struct resource console_mem_resource = {"Video RAM area" ,0 ,0 , +IORESOURCE_MEM }; +unsigned long vram_size;u16 saved1, saved2;volatile u16 *p;
@@ -193,34 +197,35 @@ static const char __init *vgacon_startupif (ORIG_VIDEO_MODE ==7 )/* Is this a monochrome display? */ { vga_vram_base =0xb0000 ; - vga_video_port_reg =0x3b4 ; - vga_video_port_val =0x3b5 ;if ((ORIG_VIDEO_EGA_BX &0xff ) !=0x10 ) { -static struct resource ega_console_resource = {"ega" ,0x3B0 ,0x3BF }; +static struct resource ega_console_resource = {"ega" ,0x3B0 ,0x3BF ,IORESOURCE_IO }; vga_video_type =VIDEO_TYPE_EGAM ; vga_vram_end =0xb8000 ; display_desc ="EGA+" ; -request_resource (&ioport_resource, &ega_console_resource); + console_resource = &ega_console_resource; }else { -static struct resource mda1_console_resource = {"mda" ,0x3B0 ,0x3BB }; -static struct resource mda2_console_resource = {"mda" ,0x3BF ,0x3BF }; +static struct resource mda1_console_resource = {"mda" ,0x3B0 ,0x3BB ,IORESOURCE_IO }; +static struct resource mda2_console_resource = {"mda" ,0x3BF ,0x3BF ,IORESOURCE_IO }; vga_video_type =VIDEO_TYPE_MDA ; vga_vram_end =0xb2000 ; display_desc ="*MDA" ; -request_resource (&ioport_resource, &mda1_console_resource); -request_resource (&ioport_resource, &mda2_console_resource); +if (pci_request_legacy_resource (NULL , &mda2_console_resource) <0 ) + goto no_vga; + console_resource = &mda1_console_resource; vga_video_font_height =14 ; } +if (pci_request_legacy_resource (NULL , console_resource) <0 ) + goto no_vga; + vga_video_port_reg = console_resource->start +0x4 ;/* 0x3b4 */ + vga_video_port_val = console_resource->start +0x5 ;/* 0x3b5 */ }else /* If not, it is color. */ { vga_can_do_color =1 ; vga_vram_base =0xb8000 ; - vga_video_port_reg =0x3d4 ; - vga_video_port_val =0x3d5 ;if ((ORIG_VIDEO_EGA_BX &0xff ) !=0x10 ) {int i;
@@ -228,15 +233,19 @@ static const char __init *vgacon_startup vga_vram_end =0xc0000 ;if (!ORIG_VIDEO_ISVGA ) { -static struct resource ega_console_resource = {"ega" ,0x3C0 ,0x3DF }; +static struct resource ega_console_resource = {"ega" ,0x3C0 ,0x3DF ,IORESOURCE_IO }; vga_video_type =VIDEO_TYPE_EGAC ; display_desc ="EGA" ; -request_resource (&ioport_resource, &ega_console_resource); + console_resource = &ega_console_resource; +if (pci_request_legacy_resource (NULL , console_resource) <0 ) + goto no_vga; }else { -static struct resource vga_console_resource = {"vga+" ,0x3C0 ,0x3DF }; +static struct resource vga_console_resource = {"vga+" ,0x3C0 ,0x3DF ,IORESOURCE_IO }; vga_video_type =VIDEO_TYPE_VGAC ; display_desc ="VGA+" ; -request_resource (&ioport_resource, &vga_console_resource); + console_resource = &vga_console_resource; +if (pci_request_legacy_resource (NULL , console_resource) <0 ) + goto no_vga;#ifdef VGA_CAN_DO_64KB /*
@@ -247,8 +256,8 @@ static const char __init *vgacon_startup*/ vga_vram_base =0xa0000 ; vga_vram_end =0xb0000 ; -outb_p (6 ,0x3ce ) ; -outb_p (6 ,0x3cf ) ; +outb_p (6 , gr_port_reg) ; +outb_p (6 , gr_port_val) ;#endif /*
@@ -258,36 +267,47 @@ static const char __init *vgacon_startup*/ for (i=0 ; i<16 ; i++) { -inb_p (0x3da ) ; -outb_p (i,0x3c0 ) ; -outb_p (i,0x3c0 ) ; +inb_p (console_resource->start +0x1a ) ;/* 0x3da */ +outb_p (i, attrib_port) ; +outb_p (i, attrib_port) ; } -outb_p (0x20 ,0x3c0 ) ; +outb_p (0x20 , attrib_port) ;/* now set the DAC registers back to their * default values */ for (i=0 ; i<16 ; i++) { -outb_p (color_table[i],0x3c8 ) ; -outb_p (default_red[i],0x3c9 ) ; -outb_p (default_grn[i],0x3c9 ) ; -outb_p (default_blu[i],0x3c9 ) ; +outb_p (color_table[i], dac_reg) ; +outb_p (default_red[i], dac_val) ; +outb_p (default_grn[i], dac_val) ; +outb_p (default_blu[i], dac_val) ; } } + vga_video_port_reg = console_resource->start +0x14 ;/* 0x3d4 */ + vga_video_port_val = console_resource->start +0x15 ;/* 0x3d5 */ }else { -static struct resource cga_console_resource = {"cga" ,0x3D4 ,0x3D5 }; +static struct resource cga_console_resource = {"cga" ,0x3D4 ,0x3D5 ,IORESOURCE_IO }; vga_video_type =VIDEO_TYPE_CGA ; vga_vram_end =0xba000 ; display_desc ="*CGA" ; -request_resource (&ioport_resource, &cga_console_resource); + console_resource = &cga_console_resource; +if (pci_request_legacy_resource (NULL , console_resource) <0 ) + goto no_vga; vga_video_font_height =8 ; + vga_video_port_reg = console_resource->start +0x0 ;/* 0x3d4 */ + vga_video_port_val = console_resource->start +0x1 ;/* 0x3d5 */ } } - vga_vram_base =VGA_MAP_MEM (vga_vram_base); - vga_vram_end =VGA_MAP_MEM (vga_vram_end); + console_mem_resource.start = vga_vram_base; + console_mem_resource.end = vga_vram_end -1 ; +pci_request_legacy_resource (NULL , &console_mem_resource); + vram_size = vga_vram_end - vga_vram_base; + vga_vram_base = (unsigned long )ioremap (console_mem_resource.start, + vram_size); + vga_vram_end = vga_vram_base + vram_size;/* * Find out if there is a graphics card present.
@@ -697,10 +717,10 @@ static int vgacon_blank(struct vc_data *#ifdef CAN_LOAD_EGA_FONTS -#define colourmap 0xa0000 +#define colourmap (vga_vram_base & ~0x1ffffUL)/* 0xa0000 */ /* Pauline Middelink <[email protected]> reports that we should use 0xA0000 for the bwmap as well.. */ -#define blackwmap 0xa0000 +#define blackwmap (vga_vram_base & ~0x1ffffUL)/* 0xa0000 */ #define cmapsz 8192 static int
@@ -713,14 +733,14 @@ vgacon_do_font_op(char *arg, int set, inint font_select =0x00 ;if (vga_video_type !=VIDEO_TYPE_EGAM ) { - charmap = (char *)VGA_MAP_MEM (colourmap); + charmap = (char *)(colourmap); beg =0x0e ;#ifdef VGA_CAN_DO_64KB if (vga_video_type ==VIDEO_TYPE_VGAC ) beg =0x06 ;#endif }else { - charmap = (char *)VGA_MAP_MEM (blackwmap); + charmap = (char *)(blackwmap); beg =0x0a ; }
include/linux/pci.h +11 -0
@@ -677,6 +677,17 @@ extern struct pci_dev *isa_bridge;#include <asm/pci.h> +#ifndef __HAVE_ARCH_LEGACY_REMAP +/* Default for architectures with a single I/O address space. */ +static inline int +pci_request_legacy_resource (struct pci_bus *bus,struct resource *res) +{ +struct resource *root = res->flags &IORESOURCE_IO ? + &ioport_resource : &iomem_resource; +return request_resource (root, res); +} +#endif +/* * If the system does not have PCI, clearly these return errors. Define * these as simple inline functions to avoid hair in drivers.
Quoted 5 lines · Ivan Kokshaysky
Here's the patch that converts
vgacon.ctopci_request_legacy_resource(). Tested on i386 and a single-bus alpha (alpha specific bits not included here).Note that it breaks ppc, as
VGA_MAP_MEM()is removed...
Ok, if I understand properly, all we have to do on PPC is to implement a pci_request_legacy_resource() that will do the right thing for legacy VGA memory as well ?
Then, please, check the return value of pci_request_legacy_resource() for getting to the VGA memory. Some machines (typically PowerMacs) simply don't give you a way to generate PCI cycles to those low memory addresses (you can't do VGA on those).
Disabling VGA dynamically depending on the machine have been a real pain until now. With that change, it will now just be a matter for our PPC implementation of pci_request_legacy_resource() to fail on machines where VGA memory can't be reached.
Ben.
Quoted 3 lines · Benjamin Herrenschmidt
Ok, if I understand properly, all we have to do on PPC is to implement a
pci_request_legacy_resource()that will do the right thing for legacy VGA memory as well ?
Exactly.
Quoted 4 lines
Then, please, check the return value of
pci_request_legacy_resource()for getting to the VGA memory. Some machines (typically PowerMacs) simply don't give you a way to generate PCI cycles to those low memory addresses (you can't do VGA on those).
I agree, it certainly needs to be fixed.
The reason why I didn't it is that i386 has 0xa0000-0xbfffff region already claimed (somewhere in arch code?), I haven't looked into this yet.
Ivan.
Quoted 4 lines · Benjamin Herrenschmidt
Disabling VGA dynamically depending on the machine have been a real pain until now. With that change, it will now just be a matter for our PPC implementation of
pci_request_legacy_resource()to fail on machines where VGA memory can't be reached.
Here's updated version of yesterday's patch that makes this possible.
- pci_request_legacy_resource() is supposed to return two error codes:
-ENXIO (no such device or address), which must be treated as fatal; -EBUSY, returned by request_resource() in the case of resource conflict, like i386 case where the startup code reserves certain low memory regions including video memory. This error can be ignored for now (at least in the vgacon driver), because resource start/end fields are correctly adjusted anyway.
- Fixed bug wrt adjusting static struct resource (thanks to Jeff for finding that). The vgacon can be started twice: early on startup and, if this fails because we assumed the wrong bus, after PCI init when we actually located the VGA card. However, static VGA resources are already "fixed" after the first try, so the second attempt fails as well.
- Make no_vga case to release VGA resources.
Ivan.
drivers/video/console/vgacon.c +76 -46
@@ -47,8 +47,8 @@#include <linux/vt_kern.h> #include <linux/selection.h> #include <linux/spinlock.h> -#include <linux/ioport.h> #include <linux/init.h> +#include <linux/pci.h> #include <asm/io.h>
@@ -66,15 +66,15 @@ static spinlock_t vga_lock = SPIN_LOCK_U*/ #undef TRIDENT_GLITCH -#define dac_reg 0x3c8 -#define dac_val 0x3c9 -#define attrib_port 0x3c0 -#define seq_port_reg 0x3c4 -#define seq_port_val 0x3c5 -#define gr_port_reg 0x3ce -#define gr_port_val 0x3cf -#define video_misc_rd 0x3cc -#define video_misc_wr 0x3c2 +#define dac_reg (console_io.start + 0x8) +#define dac_val (console_io.start + 0x9) +#define attrib_port (console_io.start + 0x0) +#define seq_port_reg (console_io.start + 0x4) +#define seq_port_val (console_io.start + 0x5) +#define gr_port_reg (console_io.start + 0xe) +#define gr_port_val (console_io.start + 0xf) +#define video_misc_rd (console_io.start + 0xc) +#define video_misc_wr (console_io.start + 0x2)/* * Interface used by the world
@@ -100,8 +100,8 @@ static unsigned long vgacon_uni_pagedir[/* Description of the hardware situation */ static unsigned long vga_vram_base;/* Base of video memory */ static unsigned long vga_vram_end;/* End of video memory */ -static u16 vga_video_port_reg;/* Video register select port */ -static u16 vga_video_port_val;/* Video register value port */ +static unsigned long vga_video_port_reg;/* Video register select port */ +static unsigned long vga_video_port_val;/* Video register value port */ static unsigned int vga_video_num_columns;/* Number of text columns */ static unsigned int vga_video_num_lines;/* Number of text lines */ static int vga_can_do_color =0 ;/* Do we support colors? */
@@ -116,7 +116,11 @@ static int vga_is_gfx;static int vga_512_chars;static int vga_video_font_height;static unsigned int vga_rolled_over =0 ; - +static struct resource console_io = { .flags =IORESOURCE_IO , }; +static struct resource console_io1 = { .name ="mda" , + .flags =IORESOURCE_IO , }; +static struct resource console_mem = { .name ="Video RAM" , + .flags =IORESOURCE_MEM , };static int __init no_scroll (char *str) {
@@ -166,11 +170,18 @@ static inline void write_vga(unsigned chstatic const char __init *vgacon_startup (void ) {const char *display_desc =NULL ; +unsigned long vram_size;u16 saved1, saved2;volatile u16 *p;if (ORIG_VIDEO_ISVGA ==VIDEO_TYPE_VLFB ) { no_vga: +if (console_io.parent) +release_resource (&console_io); +if (console_io1.parent) +release_resource (&console_io1); +if (console_mem.parent) +release_resource (&console_mem);#ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con;return conswitchp->con_startup ();
@@ -193,51 +204,57 @@ static const char __init *vgacon_startupif (ORIG_VIDEO_MODE ==7 )/* Is this a monochrome display? */ { vga_vram_base =0xb0000 ; - vga_video_port_reg =0x3b4 ; - vga_video_port_val =0x3b5 ; + console_io.start =0x3b0 ; +if ((ORIG_VIDEO_EGA_BX &0xff ) !=0x10 ) { -static struct resource ega_console_resource = {"ega" ,0x3B0 ,0x3BF }; vga_video_type =VIDEO_TYPE_EGAM ; vga_vram_end =0xb8000 ; + console_io.name ="ega" ; + console_io.end =0x3bf ; display_desc ="EGA+" ; -request_resource (&ioport_resource, &ega_console_resource); }else { -static struct resource mda1_console_resource = {"mda" ,0x3B0 ,0x3BB }; -static struct resource mda2_console_resource = {"mda" ,0x3BF ,0x3BF }; vga_video_type =VIDEO_TYPE_MDA ; vga_vram_end =0xb2000 ; display_desc ="*MDA" ; -request_resource (&ioport_resource, &mda1_console_resource); -request_resource (&ioport_resource, &mda2_console_resource); + console_io1.start =0x3bf ; + console_io1.end =0x3bf ; +if (pci_request_legacy_resource (NULL , &console_io1) + == -ENXIO ) + goto no_vga; + console_io.name ="mda" ; + console_io.end =0x3bb ; vga_video_font_height =14 ; } +if (pci_request_legacy_resource (NULL , &console_io) == -ENXIO ) + goto no_vga; + vga_video_port_reg = console_io.start +0x4 ;/* 0x3b4 */ + vga_video_port_val = console_io.start +0x5 ;/* 0x3b5 */ }else /* If not, it is color. */ { vga_can_do_color =1 ; vga_vram_base =0xb8000 ; - vga_video_port_reg =0x3d4 ; - vga_video_port_val =0x3d5 ;if ((ORIG_VIDEO_EGA_BX &0xff ) !=0x10 ) {int i; vga_vram_end =0xc0000 ; + console_io.name =ORIG_VIDEO_ISVGA ?"vga+" :"ega" ; + console_io.start =0x3c0 ; + console_io.end =0x3df ; +if (pci_request_legacy_resource (NULL , &console_io) + == -ENXIO ) + goto no_vga;if (!ORIG_VIDEO_ISVGA ) { -static struct resource ega_console_resource = {"ega" ,0x3C0 ,0x3DF }; vga_video_type =VIDEO_TYPE_EGAC ; display_desc ="EGA" ; -request_resource (&ioport_resource, &ega_console_resource); }else { -static struct resource vga_console_resource = {"vga+" ,0x3C0 ,0x3DF }; vga_video_type =VIDEO_TYPE_VGAC ; display_desc ="VGA+" ; -request_resource (&ioport_resource, &vga_console_resource); -#ifdef VGA_CAN_DO_64KB /* * get 64K rather than 32K of video RAM.
@@ -247,8 +264,8 @@ static const char __init *vgacon_startup*/ vga_vram_base =0xa0000 ; vga_vram_end =0xb0000 ; -outb_p (6 ,0x3ce ) ; -outb_p (6 ,0x3cf ) ; +outb_p (6 , gr_port_reg) ; +outb_p (6 , gr_port_val) ;#endif /*
@@ -258,36 +275,49 @@ static const char __init *vgacon_startup*/ for (i=0 ; i<16 ; i++) { -inb_p (0x3da ) ; -outb_p (i,0x3c0 ) ; -outb_p (i,0x3c0 ) ; +inb_p (console_io.start +0x1a );/* 0x3da */ +outb_p (i, attrib_port); +outb_p (i, attrib_port); } -outb_p (0x20 ,0x3c0 ) ; +outb_p (0x20 , attrib_port);/* now set the DAC registers back to their * default values */ for (i=0 ; i<16 ; i++) { -outb_p (color_table[i],0x3c8 ) ; -outb_p (default_red[i],0x3c9 ) ; -outb_p (default_grn[i],0x3c9 ) ; -outb_p (default_blu[i],0x3c9 ) ; +outb_p (color_table[i], dac_reg); +outb_p (default_red[i], dac_val); +outb_p (default_grn[i], dac_val); +outb_p (default_blu[i], dac_val); } } + vga_video_port_reg = console_io.start +0x14 ;/* 0x3d4 */ + vga_video_port_val = console_io.start +0x15 ;/* 0x3d5 */ }else { -static struct resource cga_console_resource = {"cga" ,0x3D4 ,0x3D5 }; vga_video_type =VIDEO_TYPE_CGA ; vga_vram_end =0xba000 ; display_desc ="*CGA" ; -request_resource (&ioport_resource, &cga_console_resource); + console_io.name ="cga" ; + console_io.start =0x3d4 ; + console_io.end =0x3d5 ; +if (pci_request_legacy_resource (NULL , &console_io) + == -ENXIO ) + goto no_vga; vga_video_font_height =8 ; + vga_video_port_reg = console_io.start +0x0 ;/* 0x3d4 */ + vga_video_port_val = console_io.start +0x1 ;/* 0x3d5 */ } } - vga_vram_base =VGA_MAP_MEM (vga_vram_base); - vga_vram_end =VGA_MAP_MEM (vga_vram_end); + console_mem.start = vga_vram_base; + console_mem.end = vga_vram_end -1 ; +if (pci_request_legacy_resource (NULL , &console_mem) == -ENXIO ) + goto no_vga; + vram_size = vga_vram_end - vga_vram_base; + vga_vram_base = (unsigned long )ioremap (console_mem.start, vram_size); + vga_vram_end = vga_vram_base + vram_size;/* * Find out if there is a graphics card present.
@@ -697,10 +727,10 @@ static int vgacon_blank(struct vc_data *#ifdef CAN_LOAD_EGA_FONTS -#define colourmap 0xa0000 +#define colourmap (vga_vram_base & ~0x1ffffUL)/* 0xa0000 */ /* Pauline Middelink <[email protected]> reports that we should use 0xA0000 for the bwmap as well.. */ -#define blackwmap 0xa0000 +#define blackwmap (vga_vram_base & ~0x1ffffUL)/* 0xa0000 */ #define cmapsz 8192 static int
@@ -713,14 +743,14 @@ vgacon_do_font_op(char *arg, int set, inint font_select =0x00 ;if (vga_video_type !=VIDEO_TYPE_EGAM ) { - charmap = (char *)VGA_MAP_MEM (colourmap); + charmap = (char *)(colourmap); beg =0x0e ;#ifdef VGA_CAN_DO_64KB if (vga_video_type ==VIDEO_TYPE_VGAC ) beg =0x06 ;#endif }else { - charmap = (char *)VGA_MAP_MEM (blackwmap); + charmap = (char *)(blackwmap); beg =0x0a ; }
include/linux/pci.h +11 -0
@@ -677,6 +677,17 @@ extern struct pci_dev *isa_bridge;#include <asm/pci.h> +#ifndef __HAVE_ARCH_LEGACY_REMAP +/* Default for architectures with a single I/O address space. */ +static inline int +pci_request_legacy_resource (struct pci_bus *bus,struct resource *res) +{ +struct resource *root = res->flags &IORESOURCE_IO ? + &ioport_resource : &iomem_resource; +return request_resource (root, res); +} +#endif +/* * If the system does not have PCI, clearly these return errors. Define * these as simple inline functions to avoid hair in drivers.
Quoted 7 lines · Benjamin Herrenschmidt
Quoted 4 lines
Disabling VGA dynamically depending on the machine have been a real pain until now. With that change, it will now just be a matter for our PPC implementation of
pci_request_legacy_resource()to fail on machines where VGA memory can't be reached.
Quoted 14 lines
Here's updated version of yesterday's patch that makes this possible.
-pci_request_legacy_resource()is supposed to return two error codes:
-ENXIO(no such device or address), which must be treated as fatal;-EBUSY, returned byrequest_resource()in the case of resource conflict, like i386 case where the startup code reserves certain low memory regions including video memory. This error can be ignored for now (at least in the vgacon driver), because resource start/end fields are correctly adjusted anyway.
- Fixed bug wrt adjusting static struct resource (thanks to Jeff for finding that). The vgacon can be started twice: early on startup and, if this fails because we assumed the wrong bus, after PCI init when we actually located the VGA card. However, static VGA resources are already "fixed" after the first try, so the second attempt fails as well.
- Makeno_vgacase to release VGA resources.
As a small note I really like to move vagcon.c to start to use the inline functions in include/video/vga.h. I have provisions to even use a specific register base region. I like to combine it with your work.
Quoted 3 lines · James Simmons
As a small note I really like to move
vagcon.cto start to use the inline functions ininclude/video/vga.h. I have provisions to even use a specific register base region. I like to combine it with your work.
Unfortunately, these functions won't work "as is" on all architectures. Even if the IO port space is mapped somewhere in the CPU memory space, this doesn't mean that the mapping is linear - look at parisc inX/outX functions, for example.
In other words, you cannot portably use readX/writeX instead of inX/outX.
Ivan.
Quoted 6 lines · Ivan Kokshaysky
Quoted 4 lines · Benjamin Herrenschmidt
Disabling VGA dynamically depending on the machine have been a real pain until now. With that change, it will now just be a matter for our PPC implementation of
pci_request_legacy_resource()to fail on machines where VGA memory can't be reached.
Quoted 14 lines
Here's updated version of yesterday's patch that makes this possible.
-pci_request_legacy_resource()is supposed to return two error codes:
-ENXIO(no such device or address), which must be treated as fatal;-EBUSY, returned byrequest_resource()in the case of resource conflict, like i386 case where the startup code reserves certain low memory regions including video memory. This error can be ignored for now (at least in the vgacon driver), because resource start/end fields are correctly adjusted anyway.
- Fixed bug wrt adjusting static struct resource (thanks to Jeff for finding that). The vgacon can be started twice: early on startup and, if this fails because we assumed the wrong bus, after PCI init when we actually located the VGA card. However, static VGA resources are already "fixed" after the first try, so the second attempt fails as well.
- Makeno_vgacase to release VGA resources.
I like this patch, any chance of it getting in? James, maybe you can push it in your next update to Linus? It may help our platform as well, which is ia64 with lots of PCI busses...
Thanks,
Jesse
Quoted 4 lines · Benjamin Herrenschmidt
We probably need to introduce an equivalent of ioremap for IO space. So far, what we have to deal is:
- Legacy ISA stuff unrelated to a PCI bus
Well, actually the ISA stuff *is* related to PCI bus on everything newer than 486 PCs as it's connected to PCI via PCI-to-ISA bridge. Even worse, I've found that at least two vendors offer PCI-to-ISA expansion systems (yes, these systems are limited to IO only on PCs because it clashes with another ISA bus in the same PCI domain), but this means that one can have multiple ISA busses on alpha, parisc, sparc64, ppc etc. One ISA bus per PCI IO domain. Shudder...
Quoted 6 lines
- Legacy devies on a given PCI segment (VGA, serial, IDE, ...)
What about some kind of
ioport_remap()that would take apci_busand an port range as arguments ? Ifpci_busis NULL, that would match a "legacy" ISA bus (non-PCI machine or default ISA bus for machines where that makes sense).
The problem is that vgacon driver is special - is starts very early, before PCI subsystem is probed and initialized. So we don't have pci_bus at this point.
Ivan.