|  | @@ -61,58 +61,157 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 | 
		
	
		
			
			| 61 | 61 |   ******************************************************************************
 | 
		
	
		
			
			| 62 | 62 |   */
 | 
		
	
		
			
			| 63 | 63 |  
 | 
		
	
		
			
			| 64 |  | -/** PCI root bridge I/O protocol */
 | 
		
	
		
			
			| 65 |  | -static EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *efipci;
 | 
		
	
		
			
			| 66 |  | -EFI_REQUEST_PROTOCOL ( EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL, &efipci );
 | 
		
	
		
			
			|  | 64 | +/**
 | 
		
	
		
			
			|  | 65 | + * Locate EFI PCI root bridge I/O protocol
 | 
		
	
		
			
			|  | 66 | + *
 | 
		
	
		
			
			|  | 67 | + * @v pci		PCI device
 | 
		
	
		
			
			|  | 68 | + * @ret handle		EFI PCI root bridge handle
 | 
		
	
		
			
			|  | 69 | + * @ret root		EFI PCI root bridge I/O protocol, or NULL if not found
 | 
		
	
		
			
			|  | 70 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 71 | + */
 | 
		
	
		
			
			|  | 72 | +static int efipci_root ( struct pci_device *pci, EFI_HANDLE *handle,
 | 
		
	
		
			
			|  | 73 | +			 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **root ) {
 | 
		
	
		
			
			|  | 74 | +	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
		
	
		
			
			|  | 75 | +	EFI_HANDLE *handles;
 | 
		
	
		
			
			|  | 76 | +	UINTN num_handles;
 | 
		
	
		
			
			|  | 77 | +	union {
 | 
		
	
		
			
			|  | 78 | +		void *interface;
 | 
		
	
		
			
			|  | 79 | +		EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
 | 
		
	
		
			
			|  | 80 | +	} u;
 | 
		
	
		
			
			|  | 81 | +	EFI_STATUS efirc;
 | 
		
	
		
			
			|  | 82 | +	UINTN i;
 | 
		
	
		
			
			|  | 83 | +	int rc;
 | 
		
	
		
			
			|  | 84 | +
 | 
		
	
		
			
			|  | 85 | +	/* Enumerate all handles */
 | 
		
	
		
			
			|  | 86 | +	if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol,
 | 
		
	
		
			
			|  | 87 | +			&efi_pci_root_bridge_io_protocol_guid,
 | 
		
	
		
			
			|  | 88 | +			NULL, &num_handles, &handles ) ) != 0 ) {
 | 
		
	
		
			
			|  | 89 | +		rc = -EEFI ( efirc );
 | 
		
	
		
			
			|  | 90 | +		DBGC ( pci, "EFIPCI cannot locate root bridges: %s\n",
 | 
		
	
		
			
			|  | 91 | +		       strerror ( rc ) );
 | 
		
	
		
			
			|  | 92 | +		goto err_locate;
 | 
		
	
		
			
			|  | 93 | +	}
 | 
		
	
		
			
			|  | 94 | +
 | 
		
	
		
			
			|  | 95 | +	/* Look for matching root bridge I/O protocol */
 | 
		
	
		
			
			|  | 96 | +	for ( i = 0 ; i < num_handles ; i++ ) {
 | 
		
	
		
			
			|  | 97 | +		*handle = handles[i];
 | 
		
	
		
			
			|  | 98 | +		if ( ( efirc = bs->OpenProtocol ( *handle,
 | 
		
	
		
			
			|  | 99 | +				&efi_pci_root_bridge_io_protocol_guid,
 | 
		
	
		
			
			|  | 100 | +				&u.interface, efi_image_handle, *handle,
 | 
		
	
		
			
			|  | 101 | +				EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
 | 
		
	
		
			
			|  | 102 | +			rc = -EEFI ( efirc );
 | 
		
	
		
			
			|  | 103 | +			DBGC ( pci, "EFIPCI cannot open %s: %s\n",
 | 
		
	
		
			
			|  | 104 | +			       efi_handle_name ( *handle ), strerror ( rc ) );
 | 
		
	
		
			
			|  | 105 | +			continue;
 | 
		
	
		
			
			|  | 106 | +		}
 | 
		
	
		
			
			|  | 107 | +		if ( u.root->SegmentNumber == PCI_SEG ( pci->busdevfn ) ) {
 | 
		
	
		
			
			|  | 108 | +			*root = u.root;
 | 
		
	
		
			
			|  | 109 | +			bs->FreePool ( handles );
 | 
		
	
		
			
			|  | 110 | +			return 0;
 | 
		
	
		
			
			|  | 111 | +		}
 | 
		
	
		
			
			|  | 112 | +		bs->CloseProtocol ( *handle,
 | 
		
	
		
			
			|  | 113 | +				    &efi_pci_root_bridge_io_protocol_guid,
 | 
		
	
		
			
			|  | 114 | +				    efi_image_handle, *handle );
 | 
		
	
		
			
			|  | 115 | +	}
 | 
		
	
		
			
			|  | 116 | +	DBGC ( pci, "EFIPCI found no root bridge for " PCI_FMT "\n",
 | 
		
	
		
			
			|  | 117 | +	       PCI_ARGS ( pci ) );
 | 
		
	
		
			
			|  | 118 | +	rc = -ENOENT;
 | 
		
	
		
			
			|  | 119 | +
 | 
		
	
		
			
			|  | 120 | +	bs->FreePool ( handles );
 | 
		
	
		
			
			|  | 121 | + err_locate:
 | 
		
	
		
			
			|  | 122 | +	return rc;
 | 
		
	
		
			
			|  | 123 | +}
 | 
		
	
		
			
			| 67 | 124 |  
 | 
		
	
		
			
			|  | 125 | +/**
 | 
		
	
		
			
			|  | 126 | + * Calculate EFI PCI configuration space address
 | 
		
	
		
			
			|  | 127 | + *
 | 
		
	
		
			
			|  | 128 | + * @v pci		PCI device
 | 
		
	
		
			
			|  | 129 | + * @v location		Encoded offset and width
 | 
		
	
		
			
			|  | 130 | + * @ret address		EFI PCI address
 | 
		
	
		
			
			|  | 131 | + */
 | 
		
	
		
			
			| 68 | 132 |  static unsigned long efipci_address ( struct pci_device *pci,
 | 
		
	
		
			
			| 69 | 133 |  				      unsigned long location ) {
 | 
		
	
		
			
			|  | 134 | +
 | 
		
	
		
			
			| 70 | 135 |  	return EFI_PCI_ADDRESS ( PCI_BUS ( pci->busdevfn ),
 | 
		
	
		
			
			| 71 | 136 |  				 PCI_SLOT ( pci->busdevfn ),
 | 
		
	
		
			
			| 72 | 137 |  				 PCI_FUNC ( pci->busdevfn ),
 | 
		
	
		
			
			| 73 | 138 |  				 EFIPCI_OFFSET ( location ) );
 | 
		
	
		
			
			| 74 | 139 |  }
 | 
		
	
		
			
			| 75 | 140 |  
 | 
		
	
		
			
			|  | 141 | +/**
 | 
		
	
		
			
			|  | 142 | + * Read from PCI configuration space
 | 
		
	
		
			
			|  | 143 | + *
 | 
		
	
		
			
			|  | 144 | + * @v pci		PCI device
 | 
		
	
		
			
			|  | 145 | + * @v location		Encoded offset and width
 | 
		
	
		
			
			|  | 146 | + * @ret value		Value
 | 
		
	
		
			
			|  | 147 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 148 | + */
 | 
		
	
		
			
			| 76 | 149 |  int efipci_read ( struct pci_device *pci, unsigned long location,
 | 
		
	
		
			
			| 77 | 150 |  		  void *value ) {
 | 
		
	
		
			
			|  | 151 | +	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
		
	
		
			
			|  | 152 | +	EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
 | 
		
	
		
			
			|  | 153 | +	EFI_HANDLE handle;
 | 
		
	
		
			
			| 78 | 154 |  	EFI_STATUS efirc;
 | 
		
	
		
			
			| 79 | 155 |  	int rc;
 | 
		
	
		
			
			| 80 | 156 |  
 | 
		
	
		
			
			| 81 |  | -	if ( ! efipci )
 | 
		
	
		
			
			| 82 |  | -		return -ENOTSUP;
 | 
		
	
		
			
			|  | 157 | +	/* Identify root bridge */
 | 
		
	
		
			
			|  | 158 | +	if ( ( rc = efipci_root ( pci, &handle, &root ) ) != 0 )
 | 
		
	
		
			
			|  | 159 | +		goto err_root;
 | 
		
	
		
			
			| 83 | 160 |  
 | 
		
	
		
			
			| 84 |  | -	if ( ( efirc = efipci->Pci.Read ( efipci, EFIPCI_WIDTH ( location ),
 | 
		
	
		
			
			| 85 |  | -					  efipci_address ( pci, location ), 1,
 | 
		
	
		
			
			| 86 |  | -					  value ) ) != 0 ) {
 | 
		
	
		
			
			|  | 161 | +	/* Read from configuration space */
 | 
		
	
		
			
			|  | 162 | +	if ( ( efirc = root->Pci.Read ( root, EFIPCI_WIDTH ( location ),
 | 
		
	
		
			
			|  | 163 | +					efipci_address ( pci, location ), 1,
 | 
		
	
		
			
			|  | 164 | +					value ) ) != 0 ) {
 | 
		
	
		
			
			| 87 | 165 |  		rc = -EEFI ( efirc );
 | 
		
	
		
			
			| 88 | 166 |  		DBG ( "EFIPCI config read from " PCI_FMT " offset %02lx "
 | 
		
	
		
			
			| 89 | 167 |  		      "failed: %s\n", PCI_ARGS ( pci ),
 | 
		
	
		
			
			| 90 | 168 |  		      EFIPCI_OFFSET ( location ), strerror ( rc ) );
 | 
		
	
		
			
			| 91 |  | -		return -EIO;
 | 
		
	
		
			
			|  | 169 | +		goto err_read;
 | 
		
	
		
			
			| 92 | 170 |  	}
 | 
		
	
		
			
			| 93 | 171 |  
 | 
		
	
		
			
			| 94 |  | -	return 0;
 | 
		
	
		
			
			|  | 172 | + err_read:
 | 
		
	
		
			
			|  | 173 | +	bs->CloseProtocol ( handle, &efi_pci_root_bridge_io_protocol_guid,
 | 
		
	
		
			
			|  | 174 | +			    efi_image_handle, handle );
 | 
		
	
		
			
			|  | 175 | + err_root:
 | 
		
	
		
			
			|  | 176 | +	return rc;
 | 
		
	
		
			
			| 95 | 177 |  }
 | 
		
	
		
			
			| 96 | 178 |  
 | 
		
	
		
			
			|  | 179 | +/**
 | 
		
	
		
			
			|  | 180 | + * Write to PCI configuration space
 | 
		
	
		
			
			|  | 181 | + *
 | 
		
	
		
			
			|  | 182 | + * @v pci		PCI device
 | 
		
	
		
			
			|  | 183 | + * @v location		Encoded offset and width
 | 
		
	
		
			
			|  | 184 | + * @v value		Value
 | 
		
	
		
			
			|  | 185 | + * @ret rc		Return status code
 | 
		
	
		
			
			|  | 186 | + */
 | 
		
	
		
			
			| 97 | 187 |  int efipci_write ( struct pci_device *pci, unsigned long location,
 | 
		
	
		
			
			| 98 | 188 |  		   unsigned long value ) {
 | 
		
	
		
			
			|  | 189 | +	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
 | 
		
	
		
			
			|  | 190 | +	EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
 | 
		
	
		
			
			|  | 191 | +	EFI_HANDLE handle;
 | 
		
	
		
			
			| 99 | 192 |  	EFI_STATUS efirc;
 | 
		
	
		
			
			| 100 | 193 |  	int rc;
 | 
		
	
		
			
			| 101 | 194 |  
 | 
		
	
		
			
			| 102 |  | -	if ( ! efipci )
 | 
		
	
		
			
			| 103 |  | -		return -ENOTSUP;
 | 
		
	
		
			
			|  | 195 | +	/* Identify root bridge */
 | 
		
	
		
			
			|  | 196 | +	if ( ( rc = efipci_root ( pci, &handle, &root ) ) != 0 )
 | 
		
	
		
			
			|  | 197 | +		goto err_root;
 | 
		
	
		
			
			| 104 | 198 |  
 | 
		
	
		
			
			| 105 |  | -	if ( ( efirc = efipci->Pci.Write ( efipci, EFIPCI_WIDTH ( location ),
 | 
		
	
		
			
			| 106 |  | -					   efipci_address ( pci, location ), 1,
 | 
		
	
		
			
			| 107 |  | -					   &value ) ) != 0 ) {
 | 
		
	
		
			
			|  | 199 | +	/* Read from configuration space */
 | 
		
	
		
			
			|  | 200 | +	if ( ( efirc = root->Pci.Write ( root, EFIPCI_WIDTH ( location ),
 | 
		
	
		
			
			|  | 201 | +					 efipci_address ( pci, location ), 1,
 | 
		
	
		
			
			|  | 202 | +					 &value ) ) != 0 ) {
 | 
		
	
		
			
			| 108 | 203 |  		rc = -EEFI ( efirc );
 | 
		
	
		
			
			| 109 | 204 |  		DBG ( "EFIPCI config write to " PCI_FMT " offset %02lx "
 | 
		
	
		
			
			| 110 | 205 |  		      "failed: %s\n", PCI_ARGS ( pci ),
 | 
		
	
		
			
			| 111 | 206 |  		      EFIPCI_OFFSET ( location ), strerror ( rc ) );
 | 
		
	
		
			
			| 112 |  | -		return -EIO;
 | 
		
	
		
			
			|  | 207 | +		goto err_write;
 | 
		
	
		
			
			| 113 | 208 |  	}
 | 
		
	
		
			
			| 114 | 209 |  
 | 
		
	
		
			
			| 115 |  | -	return 0;
 | 
		
	
		
			
			|  | 210 | + err_write:
 | 
		
	
		
			
			|  | 211 | +	bs->CloseProtocol ( handle, &efi_pci_root_bridge_io_protocol_guid,
 | 
		
	
		
			
			|  | 212 | +			    efi_image_handle, handle );
 | 
		
	
		
			
			|  | 213 | + err_root:
 | 
		
	
		
			
			|  | 214 | +	return rc;
 | 
		
	
		
			
			| 116 | 215 |  }
 | 
		
	
		
			
			| 117 | 216 |  
 | 
		
	
		
			
			| 118 | 217 |  PROVIDE_PCIAPI_INLINE ( efi, pci_num_bus );
 | 
		
	
	
		
			
			|  | @@ -146,6 +245,7 @@ int efipci_open ( EFI_HANDLE device, UINT32 attributes,
 | 
		
	
		
			
			| 146 | 245 |  		void *interface;
 | 
		
	
		
			
			| 147 | 246 |  	} pci_io;
 | 
		
	
		
			
			| 148 | 247 |  	UINTN pci_segment, pci_bus, pci_dev, pci_fn;
 | 
		
	
		
			
			|  | 248 | +	unsigned int busdevfn;
 | 
		
	
		
			
			| 149 | 249 |  	EFI_STATUS efirc;
 | 
		
	
		
			
			| 150 | 250 |  	int rc;
 | 
		
	
		
			
			| 151 | 251 |  
 | 
		
	
	
		
			
			|  | @@ -190,7 +290,8 @@ int efipci_open ( EFI_HANDLE device, UINT32 attributes,
 | 
		
	
		
			
			| 190 | 290 |  				    EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL );
 | 
		
	
		
			
			| 191 | 291 |  
 | 
		
	
		
			
			| 192 | 292 |  	/* Populate PCI device */
 | 
		
	
		
			
			| 193 |  | -	pci_init ( pci, PCI_BUSDEVFN ( pci_bus, pci_dev, pci_fn ) );
 | 
		
	
		
			
			|  | 293 | +	busdevfn = PCI_BUSDEVFN ( pci_segment, pci_bus, pci_dev, pci_fn );
 | 
		
	
		
			
			|  | 294 | +	pci_init ( pci, busdevfn );
 | 
		
	
		
			
			| 194 | 295 |  	if ( ( rc = pci_read_config ( pci ) ) != 0 ) {
 | 
		
	
		
			
			| 195 | 296 |  		DBGC ( device, "EFIPCI %s cannot read PCI configuration: %s\n",
 | 
		
	
		
			
			| 196 | 297 |  		       efi_handle_name ( device ), strerror ( rc ) );
 |