[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH RFC 3/9] console: add EHCI debug port based serial console
> +static void __init ehci_dbgp_init_preirq(struct serial_port *port) > +{ > + struct ehci_dbgp *dbgp = port->uart; > + u32 debug_port, offset; > + void __iomem *ehci_bar; > + > + debug_port = pci_conf_read32(0, dbgp->bus, dbgp->slot, dbgp->func, > + dbgp->cap); > + offset = (debug_port >> 16) & 0xfff; > + > + /* double check if the mem space is enabled */ > + dbgp->pci_cr = pci_conf_read8(0, dbgp->bus, dbgp->slot, dbgp->func, > + PCI_COMMAND); > + if ( !(dbgp->pci_cr & PCI_COMMAND_MEMORY) ) > + { > + dbgp->pci_cr |= PCI_COMMAND_MEMORY; > + pci_conf_write16(0, dbgp->bus, dbgp->slot, dbgp->func, PCI_COMMAND, > + dbgp->pci_cr); > + dbgp_printk("MMIO for EHCI enabled\n"); > + } > + > + /* > + * FIXME I don't have the bar size so just guess PAGE_SIZE is more > + * than enough. 1k is the biggest that was seen. > + */ > + set_fixmap_nocache(FIX_EHCI_DBGP, dbgp->bar_val); Should this have dbgp->bar_val & PAGE_MASK ? > + ehci_bar = (void __iomem *)fix_to_virt(FIX_EHCI_DBGP); > + ehci_bar += dbgp->bar_val & ~PAGE_MASK; > + dbgp_printk("ehci_bar: %p\n", ehci_bar); > + > + dbgp->ehci_caps = ehci_bar; > + dbgp->ehci_regs = ehci_bar + > + HC_LENGTH(readl(&dbgp->ehci_caps->hc_capbase)); > + dbgp->ehci_debug = ehci_bar + offset; > + > + detect_set_debug_port(dbgp); > + > + if ( ehci_dbgp_setup_preirq(dbgp) ) > + ehci_dbgp_status(dbgp, "ehci_dbgp_init_preirq complete"); > + > + port->tx_fifo_size = DBGP_MAX_PACKET; > + dbgp->lock = &port->tx_lock; > +} > + > +static void ehci_dbgp_setup_postirq(struct ehci_dbgp *dbgp) > +{ > + set_timer(&dbgp->timer, NOW() + MILLISECS(1)); > +} > + > +static void __init ehci_dbgp_init_postirq(struct serial_port *port) > +{ > + struct ehci_dbgp *dbgp = port->uart; > + > + if ( !dbgp->ehci_debug ) > + return; > + > + serial_async_transmit(port); > + > + init_timer(&dbgp->timer, ehci_dbgp_poll, port, 0); > + > + ehci_dbgp_setup_postirq(dbgp); > +} > + > +static int ehci_dbgp_check_release(struct ehci_dbgp *dbgp) > +{ > + struct ehci_dbg_port __iomem *ehci_debug = dbgp->ehci_debug; > + u32 ctrl; > + unsigned int i; > + > + if ( !ehci_debug ) > + return 0; > + > + for ( i = 0; i < DBGP_MAX_PACKET; ++i ) > + if ( dbgp->out.buf[i] ) > + return 1; > + > + /* > + * This means the console is not initialized, or should get shutdown > + * so as to allow for reuse of the USB device, which means it is time > + * to shutdown the USB debug port. > + */ > + printk(XENLOG_INFO "Releasing EHCI debug port at %02x:%02x.%u\n", > + dbgp->bus, dbgp->slot, dbgp->func); > + > + kill_timer(&dbgp->timer); > + dbgp->ehci_debug = NULL; > + > + ctrl = readl(&ehci_debug->control); > + if ( ctrl & DBGP_ENABLED ) > + { > + ctrl &= ~DBGP_CLAIM; > + writel(ctrl, &ehci_debug->control); > + } > + > + return 0; > +} > + > +static void __init ehci_dbgp_endboot(struct serial_port *port) > +{ > + ehci_dbgp_check_release(port->uart); Would it make sense to debug dom0 access to this EHCI bar? > +} > + > +static void ehci_dbgp_suspend(struct serial_port *port) > +{ > + struct ehci_dbgp *dbgp = port->uart; > + > + if ( !dbgp->ehci_debug ) > + return; > + > + stop_timer(&dbgp->timer); > + dbgp->timer.expires = 0; > + > + dbgp->pci_cr = pci_conf_read16(0, dbgp->bus, dbgp->slot, dbgp->func, > + PCI_COMMAND); > + > + dbgp->state = dbgp_unsafe; > +} > + > +static void ehci_dbgp_resume(struct serial_port *port) > +{ > + struct ehci_dbgp *dbgp = port->uart; > + > + if ( !dbgp->ehci_debug ) > + return; > + > + pci_conf_write32(0, dbgp->bus, dbgp->slot, dbgp->func, dbgp->bar, > + dbgp->bar_val); > + pci_conf_write16(0, dbgp->bus, dbgp->slot, dbgp->func, > + PCI_COMMAND, dbgp->pci_cr); > + > + ehci_dbgp_setup_preirq(dbgp); > + ehci_dbgp_setup_postirq(dbgp); > +} > + > +static struct uart_driver __read_mostly ehci_dbgp_driver = { > + .init_preirq = ehci_dbgp_init_preirq, > + .init_postirq = ehci_dbgp_init_postirq, > + .endboot = ehci_dbgp_endboot, > + .suspend = ehci_dbgp_suspend, > + .resume = ehci_dbgp_resume, > + .tx_empty = ehci_dbgp_tx_empty, > + .putc = ehci_dbgp_putc, > + .flush = ehci_dbgp_flush, > + .getc = ehci_dbgp_getc > +}; > + > +static struct ehci_dbgp ehci_dbgp = { .state = dbgp_unsafe, .phys_port = 1 }; > + > +static char __initdata opt_dbgp[30]; > +string_param("dbgp", opt_dbgp); > + > +void __init ehci_dbgp_init(void) > +{ > + struct ehci_dbgp *dbgp = &ehci_dbgp; > + u32 debug_port, offset, bar_val; > + const char *e; > + > + if ( strncmp(opt_dbgp, "ehci", 4) ) > + return; > + > + if ( isdigit(opt_dbgp[4]) || !opt_dbgp[4] ) > + { > + unsigned int num = 0; > + > + if ( opt_dbgp[4] ) > + simple_strtoul(opt_dbgp + 4, &e, 10); > + > + dbgp->cap = find_dbgp(dbgp, num); > + if ( !dbgp->cap ) > + return; > + > + dbgp_printk("Found EHCI debug port on %02x:%02x.%u\n", > + dbgp->bus, dbgp->slot, dbgp->func); > + } > + else if ( strncmp(opt_dbgp + 4, "@pci", 4) == 0 ) > + { > + unsigned long val = simple_strtoul(opt_dbgp + 8, &e, 16); > + > + dbgp->bus = val; > + if ( dbgp->bus != val || *e != ':' ) > + return; > + > + val = simple_strtoul(e + 1, &e, 16); > + if ( PCI_SLOT(PCI_DEVFN(val, 0)) != val || *e != '.' ) > + return; > + dbgp->slot = val; > + > + val = simple_strtoul(e + 1, &e, 16); > + if ( PCI_FUNC(PCI_DEVFN(0, val)) != val || *e ) > + return; > + dbgp->func = val; > + > + if ( !pci_device_detect(0, dbgp->bus, dbgp->slot, dbgp->func) ) > + return; > + > + dbgp->cap = __find_dbgp(dbgp->bus, dbgp->slot, dbgp->func); > + if ( !dbgp->cap ) > + return; > + > + dbgp_printk("Using EHCI debug port on %02x:%02x.%u\n", > + dbgp->bus, dbgp->slot, dbgp->func); > + } > + else > + return; > + > + debug_port = pci_conf_read32(0, dbgp->bus, dbgp->slot, dbgp->func, > + dbgp->cap); > + dbgp->bar = (debug_port >> 29) & 0x7; > + dbgp->bar = ((dbgp->bar - 1) * 4) + PCI_BASE_ADDRESS_0; > + offset = (debug_port >> 16) & 0xfff; > + dbgp_printk("bar: %02x offset: %03x\n", dbgp->bar, offset); > + if ( dbgp->bar < PCI_BASE_ADDRESS_0 || dbgp->bar > PCI_BASE_ADDRESS_5 ) > + { > + dbgp_printk("unsupported/invalid bar\n"); > + return; > + } > + > + dbgp->bar_val = bar_val = pci_conf_read32(0, dbgp->bus, dbgp->slot, > + dbgp->func, dbgp->bar); > + dbgp_printk("bar_val: %08x\n", bar_val); > + if ( bar_val & ~PCI_BASE_ADDRESS_MEM_MASK ) > + { > + dbgp_printk("only simple 32-bit MMIO BARs supported\n"); > + return; > + } > + bar_val &= PCI_BASE_ADDRESS_MEM_MASK; > + if ( !bar_val || !(bar_val + (bar_val & -bar_val)) ) > + { > + dbgp_printk("firmware initialization of MMIO BAR required\n"); > + return; > + } > + > + serial_register_uart(SERHND_DBGP, &ehci_dbgp_driver, dbgp); > +} > + > +int dbgp_op(const struct physdev_dbgp_op *op) > +{ > + if ( !ehci_dbgp.ehci_debug ) > + return 0; > + > + switch ( op->bus ) > + { > + case PHYSDEVOP_DBGP_BUS_UNKNOWN: > + break; > + case PHYSDEVOP_DBGP_BUS_PCI: > + if ( op->u.pci.seg || ehci_dbgp.bus != op->u.pci.bus || > + PCI_DEVFN(ehci_dbgp.slot, ehci_dbgp.func) != op->u.pci.devfn ) > + default: > + return 0; > + break; > + } > + > + switch ( op->op ) > + { > + case PHYSDEVOP_DBGP_RESET_PREPARE:a Oh, you have a handoff protocol! So how does this work without using this? Meaning if one uses Xen hypervisor EHCI with a pvops kernel that does not implement this? > + spin_lock_irq(ehci_dbgp.lock); > + ehci_dbgp.state = dbgp_unsafe; > + dbgp_wait_until_complete(&ehci_dbgp, NULL); > + spin_unlock_irq(ehci_dbgp.lock); > + > + return ehci_dbgp_check_release(&ehci_dbgp); > + > + case PHYSDEVOP_DBGP_RESET_DONE: > + return ehci_dbgp_external_startup(&ehci_dbgp) ?: 1; Oh, this is new. With the ?: it just passes on the return value from ehci_dbgp_external_startup? > + } > + > + return -ENOSYS; > +} > --- a/xen/drivers/char/serial.c > +++ b/xen/drivers/char/serial.c > @@ -265,6 +265,14 @@ int __init serial_parse_handle(char *con > { > int handle; > > + if ( !strncmp(conf, "dbgp", 4) && (!conf[4] || conf[4] == ',') ) > + { > + if ( !com[SERHND_DBGP].driver ) > + goto fail; > + > + return SERHND_DBGP | SERHND_COOKED; > + } > + > if ( strncmp(conf, "com", 3) ) > goto fail; > > --- a/xen/include/asm-x86/fixmap.h > +++ b/xen/include/asm-x86/fixmap.h > @@ -36,7 +36,15 @@ > * from the end of virtual memory backwards. > */ > enum fixed_addresses { > - FIX_RESERVED, /* Index 0 is reserved since fix_to_virt(0) > FIXADDR_TOP. > */ > + /* Index 0 is reserved since fix_to_virt(0) == FIXADDR_TOP. */ > + FIX_RESERVED, > + /* > + * Indexes using the page tables set up before entering __start_xen() > + * must be among the first (L1_PAGETABLE_ENTRIES - 1) entries. > + * These are generally those needed by the various console drivers. > + */ > + FIX_EHCI_DBGP, > + /* Everything else should go further down. */ > #ifdef __i386__ > FIX_PAE_HIGHMEM_0, > FIX_PAE_HIGHMEM_END = FIX_PAE_HIGHMEM_0 + NR_CPUS-1, > --- a/xen/include/public/physdev.h > +++ b/xen/include/public/physdev.h > @@ -312,6 +312,24 @@ struct physdev_pci_device { > typedef struct physdev_pci_device physdev_pci_device_t; > DEFINE_XEN_GUEST_HANDLE(physdev_pci_device_t); > > +#define PHYSDEVOP_DBGP_RESET_PREPARE 1 > +#define PHYSDEVOP_DBGP_RESET_DONE 2 > + > +#define PHYSDEVOP_DBGP_BUS_UNKNOWN 0 > +#define PHYSDEVOP_DBGP_BUS_PCI 1 > + > +#define PHYSDEVOP_dbgp_op 29 > +struct physdev_dbgp_op { > + /* IN */ > + uint8_t op; > + uint8_t bus; > + union { > + struct physdev_pci_device pci; > + } u; > +}; > +typedef struct physdev_dbgp_op physdev_dbgp_op_t; > +DEFINE_XEN_GUEST_HANDLE(physdev_dbgp_op_t); > + > /* > * Notify that some PIRQ-bound event channels have been unmasked. > * ** This command is obsolete since interface version 0x00030202 and is ** > --- a/xen/include/xen/serial.h > +++ b/xen/include/xen/serial.h > @@ -69,9 +69,10 @@ struct uart_driver { > }; > > /* 'Serial handles' are composed from the following fields. */ > -#define SERHND_IDX (3<<0) /* COM1 or COM2? */ > +#define SERHND_IDX (3<<0) /* COM1, COM2, or DBGP? */ > # define SERHND_COM1 (0<<0) > # define SERHND_COM2 (1<<0) > +# define SERHND_DBGP (2<<0) > #define SERHND_HI (1<<2) /* Mux/demux each transferred char by MSB. */ > #define SERHND_LO (1<<3) /* Ditto, except that the MSB is cleared. */ > #define SERHND_COOKED (1<<4) /* Newline/carriage-return translation? */ > @@ -142,9 +143,13 @@ struct ns16550_defaults { > unsigned long io_base; /* default io_base address */ > }; > void ns16550_init(int index, struct ns16550_defaults *defaults); > +void ehci_dbgp_init(void); > > void pl011_init(int index, unsigned long register_base_address); > > +struct physdev_dbgp_op; > +int dbgp_op(const struct physdev_dbgp_op *); > + > /* Baud rate was pre-configured before invoking the UART driver. */ > #define BAUD_AUTO (-1) > > > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |