/** * Transfer bits over SPI bit-bashing bus * * @v bus SPI bus * @v data_out TX data buffer (or NULL) * @v data_in RX data buffer (or NULL) * @v len Length of transfer (in @b bits) * @v endianness Endianness of this data transfer * * This issues @c len clock cycles on the SPI bus, shifting out data * from the @c data_out buffer to the MOSI line and shifting in data * from the MISO line to the @c data_in buffer. If @c data_out is * NULL, then the data sent will be all zeroes. If @c data_in is * NULL, then the incoming data will be discarded. */ static void spi_bit_transfer ( struct spi_bit_basher *spibit, const void *data_out, void *data_in, unsigned int len, int endianness ) { struct spi_bus *bus = &spibit->bus; struct bit_basher *basher = &spibit->basher; unsigned int sclk = ( ( bus->mode & SPI_MODE_CPOL ) ? 1 : 0 ); unsigned int cpha = ( ( bus->mode & SPI_MODE_CPHA ) ? 1 : 0 ); unsigned int bit_offset; unsigned int byte_offset; unsigned int byte_mask; unsigned int bit; unsigned int step; DBGC2 ( spibit, "SPIBIT %p transferring %d bits in mode %#x\n", spibit, len, bus->mode ); for ( step = 0 ; step < ( len * 2 ) ; step++ ) { /* Calculate byte offset and byte mask */ bit_offset = ( ( endianness == SPI_BIT_BIG_ENDIAN ) ? ( len - ( step / 2 ) - 1 ) : ( step / 2 ) ); byte_offset = ( bit_offset / 8 ); byte_mask = ( 1 << ( bit_offset % 8 ) ); /* Shift data in or out */ if ( sclk == cpha ) { const uint8_t *byte; /* Shift data out */ if ( data_out ) { byte = ( data_out + byte_offset ); bit = ( *byte & byte_mask ); DBGCP ( spibit, "SPIBIT %p wrote bit %d\n", spibit, ( bit ? 1 : 0 ) ); } else { bit = 0; } write_bit ( basher, SPI_BIT_MOSI, bit ); } else { uint8_t *byte; /* Shift data in */ bit = read_bit ( basher, SPI_BIT_MISO ); if ( data_in ) { DBGCP ( spibit, "SPIBIT %p read bit %d\n", spibit, ( bit ? 1 : 0 ) ); byte = ( data_in + byte_offset ); *byte &= ~byte_mask; *byte |= ( bit & byte_mask ); } } /* Toggle clock line */ spi_bit_delay(); sclk ^= 1; write_bit ( basher, SPI_BIT_SCLK, sclk ); } }
/** * Check to see if driver supports a device * * @v device EFI device handle * @ret rc Return status code */ static int efipci_supported ( EFI_HANDLE device ) { struct pci_device pci; int rc; /* Get PCI device information */ if ( ( rc = efipci_info ( device, &pci ) ) != 0 ) return rc; /* Look for a driver */ if ( ( rc = pci_find_driver ( &pci ) ) != 0 ) { DBGCP ( device, "EFIPCI %s has no driver\n", efi_handle_name ( device ) ); return rc; } DBGC ( device, "EFIPCI %s has driver \"%s\"\n", efi_handle_name ( device ), pci.id->name ); return 0; }
/** * Receive XenStore response raw data * * @v xen Xen hypervisor * @v data Data buffer, or NULL to discard data * @v len Length of data */ static void xenstore_recv ( struct xen_hypervisor *xen, void *data, size_t len ) { struct xenstore_domain_interface *intf = xen->store.intf; XENSTORE_RING_IDX cons = readl ( &intf->rsp_cons ); XENSTORE_RING_IDX prod; XENSTORE_RING_IDX idx; char *bytes = data; size_t offset = 0; size_t fill; DBGCP ( intf, "XENSTORE raw response:\n" ); /* Read one byte at a time */ while ( offset < len ) { /* Wait for data to be ready */ while ( 1 ) { prod = readl ( &intf->rsp_prod ); fill = ( prod - cons ); if ( fill > 0 ) break; DBGC2 ( xen, "." ); cpu_nap(); rmb(); } /* Read byte */ idx = MASK_XENSTORE_IDX ( cons++ ); if ( data ) bytes[offset++] = readb ( &intf->rsp[idx] ); } if ( data ) DBGCP_HDA ( intf, MASK_XENSTORE_IDX ( cons - len ), data, len ); /* Update consumer counter */ writel ( cons, &intf->rsp_cons ); wmb(); }
/** * Send XenStore request raw data * * @v xen Xen hypervisor * @v data Data buffer * @v len Length of data */ static void xenstore_send ( struct xen_hypervisor *xen, const void *data, size_t len ) { struct xenstore_domain_interface *intf = xen->store.intf; XENSTORE_RING_IDX prod = readl ( &intf->req_prod ); XENSTORE_RING_IDX cons; XENSTORE_RING_IDX idx; const char *bytes = data; size_t offset = 0; size_t fill; DBGCP ( intf, "XENSTORE raw request:\n" ); DBGCP_HDA ( intf, MASK_XENSTORE_IDX ( prod ), data, len ); /* Write one byte at a time */ while ( offset < len ) { /* Wait for space to become available */ while ( 1 ) { cons = readl ( &intf->req_cons ); fill = ( prod - cons ); if ( fill < XENSTORE_RING_SIZE ) break; DBGC2 ( xen, "." ); cpu_nap(); rmb(); } /* Write byte */ idx = MASK_XENSTORE_IDX ( prod++ ); writeb ( bytes[offset++], &intf->req[idx] ); } /* Update producer counter */ wmb(); writel ( prod, &intf->req_prod ); wmb(); }
/** * Open EFI PCI device * * @v device EFI device handle * @v attributes Protocol opening attributes * @v pci PCI device to fill in * @ret rc Return status code */ int efipci_open ( EFI_HANDLE device, UINT32 attributes, struct pci_device *pci ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; union { EFI_PCI_IO_PROTOCOL *pci_io; void *interface; } pci_io; UINTN pci_segment, pci_bus, pci_dev, pci_fn; unsigned int busdevfn; EFI_STATUS efirc; int rc; /* See if device is a PCI device */ if ( ( efirc = bs->OpenProtocol ( device, &efi_pci_io_protocol_guid, &pci_io.interface, efi_image_handle, device, attributes ) ) != 0 ) { rc = -EEFI_PCI ( efirc ); DBGCP ( device, "EFIPCI %s cannot open PCI protocols: %s\n", efi_handle_name ( device ), strerror ( rc ) ); goto err_open_protocol; } /* Get PCI bus:dev.fn address */ if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io, &pci_segment, &pci_bus, &pci_dev, &pci_fn ) ) != 0 ) { rc = -EEFI ( efirc ); DBGC ( device, "EFIPCI %s could not get PCI location: %s\n", efi_handle_name ( device ), strerror ( rc ) ); goto err_get_location; } busdevfn = PCI_BUSDEVFN ( pci_segment, pci_bus, pci_dev, pci_fn ); pci_init ( pci, busdevfn ); DBGCP ( device, "EFIPCI " PCI_FMT " is %s\n", PCI_ARGS ( pci ), efi_handle_name ( device ) ); /* Try to enable I/O cycles, memory cycles, and bus mastering. * Some platforms will 'helpfully' report errors if these bits * can't be enabled (for example, if the card doesn't actually * support I/O cycles). Work around any such platforms by * enabling bits individually and simply ignoring any errors. */ pci_io.pci_io->Attributes ( pci_io.pci_io, EfiPciIoAttributeOperationEnable, EFI_PCI_IO_ATTRIBUTE_IO, NULL ); pci_io.pci_io->Attributes ( pci_io.pci_io, EfiPciIoAttributeOperationEnable, EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL ); pci_io.pci_io->Attributes ( pci_io.pci_io, EfiPciIoAttributeOperationEnable, EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL ); /* Populate PCI device */ if ( ( rc = pci_read_config ( pci ) ) != 0 ) { DBGC ( device, "EFIPCI " PCI_FMT " cannot read PCI " "configuration: %s\n", PCI_ARGS ( pci ), strerror ( rc ) ); goto err_pci_read_config; } return 0; err_pci_read_config: err_get_location: bs->CloseProtocol ( device, &efi_pci_io_protocol_guid, efi_image_handle, device ); err_open_protocol: return rc; }