// SPDX-License-Identifier: GPL-2.0
/*
* xhci-dbgcap.c - xHCI debug capability support
*
* Copyright (C) 2017 Intel Corporation
*
* Author: Lu Baolu <baolu.lu@linux.intel.com>
*/
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/nls.h>
#include "xhci.h"
#include "xhci-trace.h"
#include "xhci-dbgcap.h"
static void dbc_free_ctx(struct device *dev, struct xhci_container_ctx *ctx)
{
if (!ctx)
return;
dma_free_coherent(dev, ctx->size, ctx->bytes, ctx->dma);
kfree(ctx);
}
/* we use only one segment for DbC rings */
static void dbc_ring_free(struct device *dev, struct xhci_ring *ring)
{
if (!ring)
return;
if (ring->first_seg && ring->first_seg->trbs) {
dma_free_coherent(dev, TRB_SEGMENT_SIZE,
ring->first_seg->trbs,
ring->first_seg->dma);
kfree(ring->first_seg);
}
kfree(ring);
}
static u32 xhci_dbc_populate_strings(struct dbc_str_descs *strings)
{
struct usb_string_descriptor *s_desc;
u32 string_length;
/* Serial string: */
s_desc = (struct usb_string_descriptor *)strings->serial;
utf8s_to_utf16s(DBC_STRING_SERIAL, strlen(DBC_STRING_SERIAL),
UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData,
DBC_MAX_STRING_LENGTH);
s_desc->bLength = (strlen(DBC_STRING_SERIAL) + 1) * 2;
s_desc->bDescriptorType = USB_DT_STRING;
string_length = s_desc->bLength;
string_length <<= 8;
/* Product string: */
s_desc = (struct usb_string_descriptor *)strings->product;
utf8s_to_utf16s(DBC_STRING_PRODUCT, strlen(DBC_STRING_PRODUCT),
UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData,
DBC_MAX_STRING_LENGTH);
s_desc->bLength = (strlen(DBC_STRING_PRODUCT) + 1) * 2;
s_desc->bDescriptorType = USB_DT_STRING;
string_length += s_desc->bLength;
string_length <<= 8;
/* Manufacture string: */
s_desc = (struct usb_string_descriptor *)strings->manufacturer;
utf8s_to_utf16s(DBC_STRING_MANUFACTURER,
strlen(DBC_STRING_MANUFACTURER),
UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData,
DBC_MAX_STRING_LENGTH);
s_desc->bLength = (strlen(DBC_STRING_MANUFACTURER) + 1) * 2;
s_desc->bDescriptorType = USB_DT_STRING;
string_length += s_desc->bLength;
string_length <<= 8;
/* String0: */
strings->string0[0] = 4;
strings->string0[1] = USB_DT_STRING;
strings->string0[2] = 0x09;
strings->string0[3] = 0x04;
string_length += 4;
return string_length;
}
static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length)
{
struct dbc_info_context *info;
struct xhci_ep_ctx *ep_ctx;
u32 dev_info;
dma_addr_t deq, dma;
unsigned int max_burst;
if (!dbc)
return;
/* Populate info Context: */
info = (struct dbc_info_context *)dbc->ctx->bytes;
dma = dbc->string_dma;
info->string0 = cpu_to_le64(dma);
info->manufacturer = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH);
info->product = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 2);
info->serial = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 3);
info->length = cpu_to_le32(string_length);
/* Populate bulk out endpoint context: */
ep_ctx = dbc_bulkout_ctx(dbc);
max_b