• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 
19 FILE_LICENCE ( GPL2_OR_LATER );
20 
21 #include <assert.h>
22 #include <gpxe/io.h>
23 #include <gpxe/efi/efi.h>
24 #include <gpxe/efi/Protocol/CpuIo.h>
25 #include <gpxe/efi/efi_io.h>
26 
27 /** @file
28  *
29  * gPXE I/O API for EFI
30  *
31  */
32 
33 /** CPU I/O protocol */
34 static EFI_CPU_IO_PROTOCOL *cpu_io;
35 EFI_REQUIRE_PROTOCOL ( EFI_CPU_IO_PROTOCOL, &cpu_io );
36 
37 /** Maximum address that can be used for port I/O */
38 #define MAX_PORT_ADDRESS 0xffff
39 
40 /**
41  * Determine whether or not address is a port I/O address
42  *
43  * @v io_addr		I/O address
44  * @v is_port		I/O address is a port I/O address
45  */
46 #define IS_PORT_ADDRESS(io_addr) \
47 	( ( ( intptr_t ) (io_addr) ) <= MAX_PORT_ADDRESS )
48 
49 /**
50  * Determine EFI CPU I/O width code
51  *
52  * @v size		Size of value
53  * @ret width		EFI width code
54  *
55  * Someone at Intel clearly gets paid by the number of lines of code
56  * they write.  No-one should ever be able to make I/O this
57  * convoluted.  The EFI_CPU_IO_PROTOCOL_WIDTH enum is my favourite
58  * idiocy.
59  */
efi_width(size_t size)60 static EFI_CPU_IO_PROTOCOL_WIDTH efi_width ( size_t size ) {
61 	switch ( size ) {
62 	case 1 :	return EfiCpuIoWidthFifoUint8;
63 	case 2 :	return EfiCpuIoWidthFifoUint16;
64 	case 4 :	return EfiCpuIoWidthFifoUint32;
65 	case 8 :	return EfiCpuIoWidthFifoUint64;
66 	default :
67 		assert ( 0 );
68 		/* I wonder what this will actually do... */
69 		return EfiCpuIoWidthMaximum;
70 	}
71 }
72 
73 /**
74  * Read from device
75  *
76  * @v io_addr		I/O address
77  * @v size		Size of value
78  * @ret data		Value read
79  */
efi_ioread(volatile void * io_addr,size_t size)80 unsigned long long efi_ioread ( volatile void *io_addr, size_t size ) {
81 	EFI_CPU_IO_PROTOCOL_IO_MEM read;
82 	unsigned long long data = 0;
83 	EFI_STATUS efirc;
84 
85 	read = ( IS_PORT_ADDRESS ( io_addr ) ?
86 		 cpu_io->Io.Read : cpu_io->Mem.Read );
87 
88 	if ( ( efirc = read ( cpu_io, efi_width ( size ),
89 			      ( intptr_t ) io_addr, 1,
90 			      ( void * ) &data ) ) != 0 ) {
91 		DBG ( "EFI I/O read at %p failed: %s\n",
92 		      io_addr, efi_strerror ( efirc ) );
93 		return -1ULL;
94 	}
95 
96 	return data;
97 }
98 
99 /**
100  * Write to device
101  *
102  * @v data		Value to write
103  * @v io_addr		I/O address
104  * @v size		Size of value
105  */
efi_iowrite(unsigned long long data,volatile void * io_addr,size_t size)106 void efi_iowrite ( unsigned long long data, volatile void *io_addr,
107 		   size_t size ) {
108 	EFI_CPU_IO_PROTOCOL_IO_MEM write;
109 	EFI_STATUS efirc;
110 
111 	write = ( IS_PORT_ADDRESS ( io_addr ) ?
112 		  cpu_io->Io.Write : cpu_io->Mem.Write );
113 
114 	if ( ( efirc = write ( cpu_io, efi_width ( size ),
115 			       ( intptr_t ) io_addr, 1,
116 			       ( void * ) &data ) ) != 0 ) {
117 		DBG ( "EFI I/O write at %p failed: %s\n",
118 		      io_addr, efi_strerror ( efirc ) );
119 	}
120 }
121 
122 /**
123  * String read from device
124  *
125  * @v io_addr		I/O address
126  * @v data		Data buffer
127  * @v size		Size of values
128  * @v count		Number of values to read
129  */
efi_ioreads(volatile void * io_addr,void * data,size_t size,unsigned int count)130 void efi_ioreads ( volatile void *io_addr, void *data,
131 		   size_t size, unsigned int count ) {
132 	EFI_CPU_IO_PROTOCOL_IO_MEM read;
133 	EFI_STATUS efirc;
134 
135 	read = ( IS_PORT_ADDRESS ( io_addr ) ?
136 		 cpu_io->Io.Read : cpu_io->Mem.Read );
137 
138 	if ( ( efirc = read ( cpu_io, efi_width ( size ),
139 			      ( intptr_t ) io_addr, count,
140 			      ( void * ) data ) ) != 0 ) {
141 		DBG ( "EFI I/O string read at %p failed: %s\n",
142 		      io_addr, efi_strerror ( efirc ) );
143 	}
144 }
145 
146 /**
147  * String write to device
148  *
149  * @v io_addr		I/O address
150  * @v data		Data buffer
151  * @v size		Size of values
152  * @v count		Number of values to write
153  */
efi_iowrites(volatile void * io_addr,const void * data,size_t size,unsigned int count)154 void efi_iowrites ( volatile void *io_addr, const void *data,
155 		    size_t size, unsigned int count ) {
156 	EFI_CPU_IO_PROTOCOL_IO_MEM write;
157 	EFI_STATUS efirc;
158 
159 	write = ( IS_PORT_ADDRESS ( io_addr ) ?
160 		 cpu_io->Io.Write : cpu_io->Mem.Write );
161 
162 	if ( ( efirc = write ( cpu_io, efi_width ( size ),
163 			       ( intptr_t ) io_addr, count,
164 			       ( void * ) data ) ) != 0 ) {
165 		DBG ( "EFI I/O write at %p failed: %s\n",
166 		      io_addr, efi_strerror ( efirc ) );
167 	}
168 }
169 
170 /**
171  * Wait for I/O-mapped operation to complete
172  *
173  */
efi_iodelay(void)174 static void efi_iodelay ( void ) {
175 	/* Write to non-existent port.  Probably x86-only. */
176 	outb ( 0, 0x80 );
177 }
178 
179 PROVIDE_IOAPI_INLINE ( efi, phys_to_bus );
180 PROVIDE_IOAPI_INLINE ( efi, bus_to_phys );
181 PROVIDE_IOAPI_INLINE ( efi, ioremap );
182 PROVIDE_IOAPI_INLINE ( efi, iounmap );
183 PROVIDE_IOAPI_INLINE ( efi, io_to_bus );
184 PROVIDE_IOAPI_INLINE ( efi, readb );
185 PROVIDE_IOAPI_INLINE ( efi, readw );
186 PROVIDE_IOAPI_INLINE ( efi, readl );
187 PROVIDE_IOAPI_INLINE ( efi, readq );
188 PROVIDE_IOAPI_INLINE ( efi, writeb );
189 PROVIDE_IOAPI_INLINE ( efi, writew );
190 PROVIDE_IOAPI_INLINE ( efi, writel );
191 PROVIDE_IOAPI_INLINE ( efi, writeq );
192 PROVIDE_IOAPI_INLINE ( efi, inb );
193 PROVIDE_IOAPI_INLINE ( efi, inw );
194 PROVIDE_IOAPI_INLINE ( efi, inl );
195 PROVIDE_IOAPI_INLINE ( efi, outb );
196 PROVIDE_IOAPI_INLINE ( efi, outw );
197 PROVIDE_IOAPI_INLINE ( efi, outl );
198 PROVIDE_IOAPI_INLINE ( efi, insb );
199 PROVIDE_IOAPI_INLINE ( efi, insw );
200 PROVIDE_IOAPI_INLINE ( efi, insl );
201 PROVIDE_IOAPI_INLINE ( efi, outsb );
202 PROVIDE_IOAPI_INLINE ( efi, outsw );
203 PROVIDE_IOAPI_INLINE ( efi, outsl );
204 PROVIDE_IOAPI ( efi, iodelay, efi_iodelay );
205 PROVIDE_IOAPI_INLINE ( efi, mb );
206