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.
--- 2.5.59/drivers/video/console/vgacon.c Tue Dec 10 09:07:11 2002
+++ linux/drivers/video/console/vgacon.c Sat Jan 25 21:27:43 2003
@@ -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_da
int 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 fontheight
are 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++) {
--- 2.5.59/include/linux/vt_buffer.h Mon Mar 18 23:37:17 2002
+++ linux/include/linux/vt_buffer.h Sat Jan 25 21:27:43 2003
@@ -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!
> 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
--
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.
On Sun, 2003-01-26 at 22:45, Martin Mares wrote:
> Hi!
>
> > 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.
> 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 ?
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
--
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.
On Mon, Jan 27, 2003 at 12:40:59AM +0100, Benjamin Herrenschmidt wrote:
> 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...
> - 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).
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.
On Mon, Jan 27, 2003 at 10:46:45AM +0100, Martin Mares wrote:
> > 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 ?
>
> 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):
int
legacy_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);
}
void
legacy_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.
On Mon, 2003-01-27 at 11:40, Ivan Kokshaysky wrote:
> 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.
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.
On Mon, Jan 27, 2003 at 06:55:04PM +0100, Benjamin Herrenschmidt wrote:
> 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.
On Tue, 28 Jan 2003, Ivan Kokshaysky wrote:
> On Mon, Jan 27, 2003 at 06:55:04PM +0100, Benjamin Herrenschmidt wrote:
> > 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.
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
On Tue, Jan 28, 2003 at 10:32:53AM +0100, Geert Uytterhoeven wrote:
> 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.
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 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);
}
#infdef
This can be overridden in <asm/pci.h>.
Ivan.
On Tue, 28 Jan 2003, Ivan Kokshaysky wrote:
> On Tue, Jan 28, 2003 at 10:32:53AM +0100, Geert Uytterhoeven wrote:
> > 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.
>
> 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 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);
> }
> #infdef
That's OK for me.
> 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
On Tue, Jan 28, 2003 at 11:27:21AM +0100, Geert Uytterhoeven wrote:
> > 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.
diff -urpN 2.5.59/drivers/video/console/vgacon.c linux/drivers/video/console/vgacon.c
--- 2.5.59/drivers/video/console/vgacon.c Fri Jan 17 05:22:05 2003
+++ linux/drivers/video/console/vgacon.c Tue Jan 28 15:54:41 2003
@@ -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 ch
static 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_startup
if (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, in
int 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;
}
diff -urpN 2.5.59/include/linux/pci.h linux/include/linux/pci.h
--- 2.5.59/include/linux/pci.h Fri Jan 17 05:22:08 2003
+++ linux/include/linux/pci.h Tue Jan 28 15:53:02 2003
@@ -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.
On Tue, 2003-01-28 at 18:10, Ivan Kokshaysky wrote:
> 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...
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.
On Tue, Jan 28, 2003 at 06:23:15PM +0100, Benjamin Herrenschmidt wrote:
> 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.
> 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.
On Tue, Jan 28, 2003 at 06:23:15PM +0100, Benjamin Herrenschmidt wrote:
> 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.
diff -urpN 2.5.59/drivers/video/console/vgacon.c linux/drivers/video/console/vgacon.c
--- 2.5.59/drivers/video/console/vgacon.c Fri Jan 17 05:22:05 2003
+++ linux/drivers/video/console/vgacon.c Wed Jan 29 16:40:58 2003
@@ -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 ch
static 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_startup
if (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, in
int 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;
}
diff -urpN 2.5.59/include/linux/pci.h linux/include/linux/pci.h
--- 2.5.59/include/linux/pci.h Fri Jan 17 05:22:08 2003
+++ linux/include/linux/pci.h Tue Jan 28 15:53:02 2003
@@ -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.
> On Tue, Jan 28, 2003 at 06:23:15PM +0100, Benjamin Herrenschmidt wrote:
> > 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.
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.
On Wed, Jan 29, 2003 at 06:15:36PM +0000, James Simmons wrote:
> 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.
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.
On Wed, Jan 29, 2003 at 07:06:47PM +0300, Ivan Kokshaysky wrote:
> On Tue, Jan 28, 2003 at 06:23:15PM +0100, Benjamin Herrenschmidt wrote:
> > 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.
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