[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.