Index: sys/boot/i386/libi386/elf32_freebsd.c =================================================================== --- sys/boot/i386/libi386/elf32_freebsd.c (revision 224448) +++ sys/boot/i386/libi386/elf32_freebsd.c (working copy) @@ -55,6 +55,7 @@ elf32_exec(struct preloaded_file *fp) { struct file_metadata *md; Elf_Ehdr *ehdr; + char *usb_takeover; vm_offset_t entry, bootinfop, modulep, kernend; int boothowto, err, bootdev; @@ -65,6 +66,15 @@ elf32_exec(struct preloaded_file *fp) err = bi_load32(fp->f_args, &boothowto, &bootdev, &bootinfop, &modulep, &kernend); if (err != 0) return(err); + + usb_takeover = getenv("usb_early_takeover"); + if (usb_takeover == NULL || strtol(usb_takeover, NULL, 0) != 0) { +#ifdef DEBUG + printf("Disable legacy USB support ...\n"); +#endif + usb_early_takeover(); + } + entry = ehdr->e_entry & 0xffffff; #ifdef DEBUG Index: sys/boot/i386/libi386/elf64_freebsd.c =================================================================== --- sys/boot/i386/libi386/elf64_freebsd.c (revision 224448) +++ sys/boot/i386/libi386/elf64_freebsd.c (working copy) @@ -73,6 +73,7 @@ elf64_exec(struct preloaded_file *fp) { struct file_metadata *md; Elf_Ehdr *ehdr; + char *usb_takeover; vm_offset_t modulep, kernend; int err; int i; @@ -85,6 +86,14 @@ elf64_exec(struct preloaded_file *fp) if (err != 0) return(err); + usb_takeover = getenv("usb_early_takeover"); + if (usb_takeover == NULL || strtol(usb_takeover, NULL, 0) != 0) { +#ifdef DEBUG + printf("Disable legacy USB support ...\n"); +#endif + usb_early_takeover(); + } + bzero(PT4, PAGE_SIZE); bzero(PT3, PAGE_SIZE); bzero(PT2, PAGE_SIZE); Index: sys/boot/i386/libi386/libi386.h =================================================================== --- sys/boot/i386/libi386/libi386.h (revision 224448) +++ sys/boot/i386/libi386/libi386.h (working copy) @@ -102,9 +102,15 @@ extern vm_offset_t memtop_copyin; /* memtop less h extern uint32_t high_heap_size; /* extended memory region available */ extern vm_offset_t high_heap_base; /* for use as the heap */ +#define BIOSPCI_BYTE 0 +#define BIOSPCI_WORD 1 +#define BIOSPCI_DWORD 2 + int biospci_find_devclass(uint32_t class, int index, uint32_t *locator); int biospci_write_config(uint32_t locator, int offset, int width, uint32_t val); int biospci_read_config(uint32_t locator, int offset, int width, uint32_t *val); +int biospci_read(uint32_t base, int offset, int width); +void biospci_write(uint32_t base, int offset, int width, int val); void biosacpi_detect(void); @@ -120,3 +126,4 @@ int bi_load32(char *args, int *howtop, int *bootde int bi_load64(char *args, vm_offset_t *modulep, vm_offset_t *kernend); void pxe_enable(void *pxeinfo); +void usb_early_takeover(void); Index: sys/boot/i386/libi386/biospci.c =================================================================== --- sys/boot/i386/libi386/biospci.c (revision 224448) +++ sys/boot/i386/libi386/biospci.c (working copy) @@ -32,7 +32,9 @@ __FBSDID("$FreeBSD$"); */ #include +#include #include +#include #include #include #include @@ -118,6 +120,14 @@ static struct pci_progif progif_firewire[] = { {-1, NULL} }; +static struct pci_progif progif_usb[] = { + {0x00, "UHCI"}, + {0x10, "OHCI"}, + {0x20, "EHCI"}, + {0x30, "XHCI"}, + {-1, NULL} +}; + struct pci_subclass { int ps_subclass; @@ -168,7 +178,7 @@ static struct pci_subclass subclass_serial[] = { {0x0, "FireWire", progif_firewire}, {0x1, "ACCESS.bus", progif_null}, {0x2, "SSA", progif_null}, - {0x3, "USB", progif_null}, + {0x3, "USB", progif_usb}, {0x4, "Fibrechannel", progif_null}, {-1, NULL, NULL} }; @@ -245,7 +255,7 @@ biospci_enumerate(void) break; /* Read the device identifier from the nominated device */ - err = biospci_read_config(locator, 0, 2, &devid); + err = biospci_read_config(locator, 0, BIOSPCI_DWORD, &devid); if (err != 0) break; @@ -341,3 +351,100 @@ biospci_read_config(uint32_t locator, int offset, return (0); } +static __inline int +biospci_io_read(uint32_t base, int offset, int width) +{ + uint32_t reg; + + reg = (base & PCIM_BAR_IO_BASE) + offset; + switch (width) { + case BIOSPCI_BYTE: + return (inb(reg)); + case BIOSPCI_WORD: + return (inw(reg)); + case BIOSPCI_DWORD: + return (inl(reg)); + default: + panic("unsupported I/O width %d\n", width); + } +} + +static __inline void +biospci_io_write(uint32_t base, int offset, int width, int val) +{ + uint32_t reg; + + reg = (base & PCIM_BAR_IO_BASE) + offset; + switch (width) { + case BIOSPCI_BYTE: + outb(reg, val); + break; + case BIOSPCI_WORD: + outw(reg, val); + break; + case BIOSPCI_DWORD: + outl(reg, val); + break; + default: + panic("unsupported I/O width %d\n", width); + } +} + +static __inline int +biospci_mem_read(uint32_t base, int offset, int width) +{ + uint32_t reg; + + reg = (base & PCIM_BAR_MEM_BASE) + offset; + switch (width) { + case BIOSPCI_BYTE: + return (*(volatile uint8_t *)PTOV(reg)); + case BIOSPCI_WORD: + return (*(volatile uint16_t *)PTOV(reg)); + case BIOSPCI_DWORD: + return (*(volatile uint32_t *)PTOV(reg)); + default: + panic("unsupported I/O width %d\n", width); + } +} + +static __inline void +biospci_mem_write(uint32_t base, int offset, int width, int val) +{ + uint32_t reg; + + reg = (base & PCIM_BAR_MEM_BASE) + offset; + switch (width) { + case BIOSPCI_BYTE: + *(volatile uint8_t *)PTOV(reg) = val; + break; + case BIOSPCI_WORD: + *(volatile uint16_t *)PTOV(reg) = val; + break; + case BIOSPCI_DWORD: + *(volatile uint32_t *)PTOV(reg) = val; + break; + default: + panic("unsupported I/O width %d\n", width); + } +} + +int +biospci_read(uint32_t base, int offset, int width) +{ + + if (PCI_BAR_MEM(base)) + return (biospci_mem_read(base, offset, width)); + else + return (biospci_io_read(base, offset, width)); +} + +void +biospci_write(uint32_t base, int offset, int width, int val) +{ + + if (PCI_BAR_MEM(base)) + biospci_mem_write(base, offset, width, val); + else + biospci_io_write(base, offset, width, val); +} Index: sys/boot/i386/libi386/usb.c =================================================================== --- sys/boot/i386/libi386/usb.c (revision 0) +++ sys/boot/i386/libi386/usb.c (revision 0) @@ -0,0 +1,271 @@ +/*- + * Copyright (c) 2009 Andriy Gapon + * Copyright (c) 2011 Hans Petter Selasky + * Copyright (c) 2011 Jung-uk Kim + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include "libi386.h" + +#define DELAY(x) delay(x) + +static int pci_usb_progif[] = { + PCIP_SERIALBUS_USB_UHCI, + PCIP_SERIALBUS_USB_OHCI, + PCIP_SERIALBUS_USB_EHCI, + PCIP_SERIALBUS_USB_XHCI +}; +#define USB_PROGIF (sizeof(pci_usb_progif) / sizeof(pci_usb_progif[0])) + +/* XXX TBD */ +#define USB_MAX_DEVS 32 + +/* Perform early OHCI takeover from SMM. */ +static void +ohci_early_takeover(uint32_t locator) +{ + uint32_t base, ctrl; + int error, i; + + error = biospci_read_config(locator, PCIR_BAR(0), BIOSPCI_DWORD, &base); + if (error) { + printf("cannot read PCI conf, loc %x, reg %x\n", locator, + PCIR_BAR(0)); + return; + } + ctrl = biospci_read(base, OHCI_CONTROL, BIOSPCI_DWORD); + if ((ctrl & OHCI_IR) == 0) + return; +#ifdef DEBUG + printf("OHCI: SMM active, request owner change\n"); +#endif + biospci_write(base, OHCI_COMMAND_STATUS, BIOSPCI_DWORD, OHCI_OCR); + for (i = 0; i < 100 && (ctrl & OHCI_IR) != 0; i++) { + DELAY(1000); + ctrl = biospci_read(base, OHCI_CONTROL, BIOSPCI_DWORD); + } + if ((ctrl & OHCI_IR) != 0) { +#ifdef DEBUG + printf("OHCI: SMM does not respond, resetting\n"); +#endif + biospci_write(base, OHCI_CONTROL, BIOSPCI_DWORD, + OHCI_HCFS_RESET); + } + + /* Disable interrupts. */ + biospci_write(base, OHCI_INTERRUPT_DISABLE, BIOSPCI_DWORD, + OHCI_ALL_INTRS); +} + +/* Perform early UHCI takeover from SMM. */ +static void +uhci_early_takeover(uint32_t locator) +{ + uint32_t base; + int error; + + /* + * Set the PIRQD enable bit and switch off all the others. We don't + * want legacy support to interfere with us XXX Does this also mean + * that the BIOS won't touch the keyboard anymore if it is connected + * to the ports of the root hub? + */ + error = biospci_write_config(locator, PCI_LEGSUP, BIOSPCI_WORD, + PCI_LEGSUP_USBPIRQDEN); + if (error) { + printf("cannot write PCI conf, loc %x, reg %x\n", locator, + PCI_LEGSUP); + return; + } + + /* Disable interrupts. */ + error = biospci_read_config(locator, PCI_UHCI_BASE_REG, BIOSPCI_DWORD, + &base); + if (error) { + printf("cannot read PCI conf, loc %x, reg %x\n", locator, + PCI_UHCI_BASE_REG); + return; + } + biospci_write(base, UHCI_INTR, BIOSPCI_WORD, 0); +} + +/* Perform early EHCI takeover from SMM. */ +static void +ehci_early_takeover(uint32_t locator) +{ + uint32_t base, bios_sem, cparams, eec; + uint8_t eecp, offs; + int error, i; + + error = biospci_read_config(locator, PCIR_BAR(0), BIOSPCI_DWORD, &base); + if (error) { + printf("cannot read PCI conf, loc %x, reg %x\n", locator, + PCIR_BAR(0)); + return; + } + cparams = biospci_read(base, EHCI_HCCPARAMS, BIOSPCI_DWORD); + + /* Synchronise with the BIOS if it owns the controller. */ + for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; + eecp = EHCI_EECP_NEXT(eec)) { + error = biospci_read_config(locator, eecp, BIOSPCI_DWORD, &eec); + if (error) { + printf("cannot read PCI conf, loc %x, reg %x\n", + locator, eecp); + break; + } + if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) + continue; + error = biospci_read_config(locator, + eecp + EHCI_LEGSUP_BIOS_SEM, BIOSPCI_BYTE, &bios_sem); + if (error) { + printf("cannot read PCI conf, loc %x, reg %x\n", + locator, eecp + EHCI_LEGSUP_BIOS_SEM); + break; + } + if (bios_sem == 0) + continue; +#ifdef DEBUG + printf("EHCI: SMM active, request owner change\n"); +#endif + error = biospci_write_config(locator, eecp + EHCI_LEGSUP_OS_SEM, + BIOSPCI_BYTE, 1); + if (error) { + printf("cannot write PCI conf, loc %x, reg %x\n", + locator, eecp + EHCI_LEGSUP_OS_SEM); + break; + } + for (i = 0; i < 100 && bios_sem != 0; i++) { + DELAY(1000); + error = biospci_read_config(locator, + eecp + EHCI_LEGSUP_BIOS_SEM, BIOSPCI_BYTE, + &bios_sem); + if (error) { + printf("cannot read PCI conf, loc %x, reg %x\n", + locator, eecp + EHCI_LEGSUP_BIOS_SEM); + break; + } + } +#ifdef DEBUG + if (bios_sem != 0) + printf("EHCI: SMM does not respond\n"); +#endif + + /* Disable interrupts. */ + offs = EHCI_CAPLENGTH(biospci_read(base, + EHCI_CAPLEN_HCIVERSION, BIOSPCI_DWORD)); + biospci_write(base, offs + EHCI_USBINTR, BIOSPCI_DWORD, 0); + } +} + +/* Perform early XHCI takeover from SMM. */ +static void +xhci_early_takeover(uint32_t locator) +{ + uint32_t base, cparams, eec; + uint8_t bios_sem, eecp, offs; + int error, i; + + error = biospci_read_config(locator, PCIR_BAR(0), BIOSPCI_DWORD, &base); + if (error) { + printf("cannot read PCI conf, loc %x, reg %x\n", locator, + PCIR_BAR(0)); + return; + } + cparams = biospci_read(base, XHCI_HCSPARAMS0, BIOSPCI_DWORD); + + eec = -1; + + /* Synchronise with the BIOS if it owns the controller. */ + for (eecp = XHCI_HCS0_XECP(cparams) << 2; + eecp != 0 && XHCI_XECP_NEXT(eec); + eecp += XHCI_XECP_NEXT(eec) << 2) { + eec = biospci_read(base, eecp, BIOSPCI_DWORD); + if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) + continue; + bios_sem = biospci_read(base, eecp + XHCI_XECP_BIOS_SEM, + BIOSPCI_BYTE); + if (bios_sem == 0) + continue; +#ifdef DEBUG + printf("XHCI: SMM active, request owner change\n"); +#endif + biospci_write(base, eecp + XHCI_XECP_OS_SEM, BIOSPCI_BYTE, 1); + + /* Wait a maximum of 5 seconds. */ + for (i = 0; i < 5000 && bios_sem != 0; i++) { + DELAY(1000); + bios_sem = biospci_read(base, + eecp + XHCI_XECP_BIOS_SEM, BIOSPCI_BYTE); + } +#ifdef DEBUG + if (bios_sem != 0) + printf("XHCI: SMM does not respond\n"); +#endif + + /* Disable interrupts. */ + offs = biospci_read(base, XHCI_CAPLENGTH, BIOSPCI_BYTE); + biospci_write(base, offs + XHCI_USBCMD, BIOSPCI_DWORD, 0); + biospci_read(base, offs + XHCI_USBSTS, BIOSPCI_DWORD); + } +} + +void +usb_early_takeover(void) +{ + uint32_t class, locator, progif; + int i, j; + + for (i = 0; i < USB_PROGIF; i++) + for (j = 0; j < USB_MAX_DEVS; j++) { + progif = pci_usb_progif[i]; + class = (PCIC_SERIALBUS << 16) | + (PCIS_SERIALBUS_USB << 8) | progif; + if (biospci_find_devclass(class, j, &locator) == 0) { + switch (progif) { + case PCIP_SERIALBUS_USB_UHCI: + uhci_early_takeover(locator); + break; + case PCIP_SERIALBUS_USB_OHCI: + ohci_early_takeover(locator); + break; + case PCIP_SERIALBUS_USB_EHCI: + ehci_early_takeover(locator); + break; + case PCIP_SERIALBUS_USB_XHCI: + xhci_early_takeover(locator); + break; + } + } + } +} Property changes on: sys/boot/i386/libi386/usb.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/boot/i386/libi386/Makefile =================================================================== --- sys/boot/i386/libi386/Makefile (revision 224448) +++ sys/boot/i386/libi386/Makefile (working copy) @@ -8,7 +8,7 @@ SRCS= biosacpi.c bioscd.c biosdisk.c biosmem.c bio comconsole.c devicename.c elf32_freebsd.c \ elf64_freebsd.c \ i386_copy.c i386_module.c nullconsole.c pxe.c pxetramp.s \ - smbios.c time.c vidconsole.c amd64_tramp.S spinconsole.c + smbios.c time.c usb.c vidconsole.c amd64_tramp.S spinconsole.c # Enable PXE TFTP or NFS support, not both. .if defined(LOADER_TFTP_SUPPORT)