Re: [RESEND PATCH 1/4] usb: dbc: early driver for xhci debug capability

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On 09/20/2016 09:54 PM, Mathias Nyman wrote:
> On 29.08.2016 08:26, Lu Baolu wrote:
>> xHCI debug capability (DbC) is an optional but standalone
>> functionality provided by an xHCI host controller. Software
>> learns this capability by walking through the extended
>> capability list of the host. xHCI specification describes
>> DbC in section 7.6.
>>
>> This patch introduces the code to probe and initialize the
>> debug capability hardware during early boot. With hardware
>> initialized, the debug target (system on which this code is
>> running) will present a debug device through the debug port
>> (normally the first USB3 port). The debug device is fully
>> compliant with the USB framework and provides the equivalent
>> of a very high performance (USB3) full-duplex serial link
>> between the debug host and target. The DbC functionality is
>> independent of xHCI host. There isn't any precondition from
>> xHCI host side for DbC to work.
>>
>> This patch also includes bulk out and bulk in interfaces.
>> These interfaces could be used to implement early printk
>> bootconsole or hook to various system debuggers.
>>
>> This code is designed to be only used for kernel debugging
>> when machine crashes very early before the console code is
>> initialized. For normal operation it is not recommended.
>>
>> Cc: Mathias Nyman <mathias.nyman@xxxxxxxxxxxxxxx>
>> Signed-off-by: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx>
>> ---
>
> Some comments inline

Thank you for reviewing my patch.

>
>> +
>> +#ifdef XDBC_TRACE
>> +#define    xdbc_trace    trace_printk
>> +#else
>> +static inline void xdbc_trace(const char *fmt, ...) { }
>> +#endif /* XDBC_TRACE */
>
> I guess there's probably no better way to enable/disable debug messages for this
> driver this early, and ehci-dbgp does the same.
>
> So I guess It's ok, but it still looks weird
>
>> +
>> +static void xdbc_early_delay(unsigned long count)
>> +{
>> +    u8 val;
>> +
>> +    val = inb(0x80);
>> +    while (count-- > 0)
>> +        outb(val, 0x80);
>> +}
>> +
>> +static void xdbc_runtime_delay(unsigned long count)
>> +{
>> +    udelay(count);
>> +}
>> +
>
> Glad to see the addition of this runtime_delay in addition
> to the hack of reading port 0x80 for a 1us delay.
>
> And that the early_delay is only used for as long as it must.
>
>
>> +static int xdbc_handle_external_reset(void)
>> +{
>> +    u32 ctrl;
>> +    int ret;
>> +
>> +    writel(0, &xdbc.xdbc_reg->control);
>> +    ret = handshake(&xdbc.xdbc_reg->control, CTRL_DCE, 0, 100000, 10);
>> +    if (ret)
>> +        return ret;
>> +
>> +    xdbc_mem_init();
>> +    mmiowb();
>> +
>> +    ctrl = readl(&xdbc.xdbc_reg->control);
>> +    writel(ctrl | CTRL_DCE | CTRL_PED, &xdbc.xdbc_reg->control);
>> +    ret = handshake(&xdbc.xdbc_reg->control,
>> +            CTRL_DCE, CTRL_DCE, 100000, 10);
>> +    if (ret)
>> +        return ret;
>> +
>> +    if (xdbc.vendor == PCI_VENDOR_ID_INTEL)
>> +        xdbc_do_reset_debug_port(xdbc.port_number, 1);
>> +
>> +    /* wait for port connection */
>> +    ret = handshake(&xdbc.xdbc_reg->portsc,
>> +            PORTSC_CCS, PORTSC_CCS, 5000000, 10);
>> +    if (ret)
>> +        return ret;
>> +
>> +    /* wait for debug device to be configured */
>> +    ret = handshake(&xdbc.xdbc_reg->control,
>> +            CTRL_DCR, CTRL_DCR, 5000000, 10);
>> +    if (ret)
>> +        return ret;
>> +
>> +    xdbc.flags |= XDBC_FLAGS_INITIALIZED | XDBC_FLAGS_CONFIGURED;
>> +
>> +    xdbc_bulk_transfer(NULL, XDBC_MAX_PACKET, true);
>> +
>> +    return 0;
>> +}
>> +
> ...
>
>> +static int __init xdbc_early_start(void)
>> +{
>> +    u32 ctrl, status;
>> +    int ret;
>> +
>> +    ctrl = readl(&xdbc.xdbc_reg->control);
>> +    writel(ctrl | CTRL_DCE | CTRL_PED, &xdbc.xdbc_reg->control);
>> +    ret = handshake(&xdbc.xdbc_reg->control,
>> +            CTRL_DCE, CTRL_DCE, 100000, 100);
>> +    if (ret) {
>> +        pr_notice("falied to initialize hardware\n");
>> +        return ret;
>> +    }
>> +
>> +    /* reset port to avoid bus hang */
>> +    if (xdbc.vendor == PCI_VENDOR_ID_INTEL)
>> +        xdbc_reset_debug_port();
>> +
>> +    /* wait for port connection */
>> +    ret = handshake(&xdbc.xdbc_reg->portsc,
>> +            PORTSC_CCS, PORTSC_CCS, 5000000, 100);
>> +    if (ret) {
>> +        pr_notice("waiting for connection timed out\n");
>> +        return ret;
>> +    }
>> +
>> +    /* wait for debug device to be configured */
>> +    ret = handshake(&xdbc.xdbc_reg->control,
>> +            CTRL_DCR, CTRL_DCR, 5000000, 100);
>> +    if (ret) {
>> +        pr_notice("waiting for device configuration timed out\n");
>> +        return ret;
>> +    }
>> +
>> +    /* port should have a valid port# */
>> +    status = readl(&xdbc.xdbc_reg->status);
>> +    if (!DCST_DPN(status)) {
>> +        pr_notice("invalid root hub port number\n");
>> +        return -ENODEV;
>> +    }
>> +
>> +    xdbc.port_number = DCST_DPN(status);
>> +
>> +    pr_notice("DbC is running now, control 0x%08x port ID %d\n",
>> +          readl(&xdbc.xdbc_reg->control), xdbc.port_number);
>> +
>> +    return 0;
>> +}
>
>
> xdbc_early_start() and xdbc_handle_external_reset() have a lot of duplicate code
> , checking DCE, resetting the port, wait for CCE and wait for DCR.
>
> Maybe put the common parts in a separate function?

Yes. I agree. Those are duplicated. I will put them in a common function.

>
>> +static void xdbc_scrub_function(struct work_struct *work)
>> +{
>> +    unsigned long flags;
>> +    int ret;
>> +
>> +    /*
>> +     * DbC is running, check the event ring and
>> +     * handle the events.
>> +     */
>> +    if (readl(&xdbc.xdbc_reg->control) & CTRL_DRC) {
>> +        spin_lock_irqsave(&xdbc.lock, flags);
>> +        xdbc_handle_events();
>> +        spin_unlock_irqrestore(&xdbc.lock, flags);
>> +    }
>> +
>> +    /*
>> +     * It's time to shutdown DbC, so that the debug
>> +     * port could be reused by the host controller.
>> +     */
>> +    if (unlikely(early_xdbc_console.index == -1 ||
>> +             (early_xdbc_console.flags & CON_BOOT))) {
>> +        writel(0, &xdbc.xdbc_reg->control);
>> +        xdbc_trace("hardware not used any more\n");
>> +        return;
>
> Shouldn't we free rings etc here as well?
> we won't queue anymore work after this, right?

Right. I should free all the resources when the hardware will
not be used any more.

>
>> +    }
>> +
>> +    /*
>> +     * External reset happened. Need to restart the
>> +     * debugging hardware.
>> +     */
>> +    if (unlikely(!(readl(&xdbc.xdbc_reg->control) & CTRL_DCE))) {
>> +        xdbc.flags &= ~(XDBC_FLAGS_INITIALIZED
>> +                | XDBC_FLAGS_CONFIGURED);
>> +        ret = xdbc_handle_external_reset();
>> +        if (ret) {
>> +            xdbc_trace("hardware failed to recover\n");
>> +            return;
>
> And here?

The same thing as above.

>
>> +        }
>> +    }
>> +
>> +    queue_delayed_work(xdbc_wq, &xdbc.scrub, usecs_to_jiffies(100));
>> +}
>> +
>
> -Mathias
>
>
>

Thanks for your review again.

Best regards,
Lu Baolu
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux