15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 202ec8a09SLee Jones /* 3aeb9dd1dSLu Baolu * xhci-dbc.c - xHCI debug capability early driver 4aeb9dd1dSLu Baolu * 5aeb9dd1dSLu Baolu * Copyright (C) 2016 Intel Corporation 6aeb9dd1dSLu Baolu * 7aeb9dd1dSLu Baolu * Author: Lu Baolu <baolu.lu@linux.intel.com> 8aeb9dd1dSLu Baolu */ 9aeb9dd1dSLu Baolu 10aeb9dd1dSLu Baolu #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 11aeb9dd1dSLu Baolu 12aeb9dd1dSLu Baolu #include <linux/console.h> 13aeb9dd1dSLu Baolu #include <linux/pci_regs.h> 14aeb9dd1dSLu Baolu #include <linux/pci_ids.h> 152013288fSMike Rapoport #include <linux/memblock.h> 16aeb9dd1dSLu Baolu #include <linux/io.h> 17796eed4bSChunfeng Yun #include <linux/iopoll.h> 18aeb9dd1dSLu Baolu #include <asm/pci-direct.h> 19aeb9dd1dSLu Baolu #include <asm/fixmap.h> 20aeb9dd1dSLu Baolu #include <linux/bcd.h> 21aeb9dd1dSLu Baolu #include <linux/export.h> 22aeb9dd1dSLu Baolu #include <linux/module.h> 23aeb9dd1dSLu Baolu #include <linux/delay.h> 24aeb9dd1dSLu Baolu #include <linux/kthread.h> 25f0f705fcSLee Jones #include <linux/usb/xhci-dbgp.h> 26aeb9dd1dSLu Baolu 27aeb9dd1dSLu Baolu #include "../host/xhci.h" 28aeb9dd1dSLu Baolu #include "xhci-dbc.h" 29aeb9dd1dSLu Baolu 30aeb9dd1dSLu Baolu static struct xdbc_state xdbc; 31aeb9dd1dSLu Baolu static bool early_console_keep; 32aeb9dd1dSLu Baolu 33aeb9dd1dSLu Baolu #ifdef XDBC_TRACE 34aeb9dd1dSLu Baolu #define xdbc_trace trace_printk 35aeb9dd1dSLu Baolu #else 36aeb9dd1dSLu Baolu static inline void xdbc_trace(const char *fmt, ...) { } 37aeb9dd1dSLu Baolu #endif /* XDBC_TRACE */ 38aeb9dd1dSLu Baolu 39aeb9dd1dSLu Baolu static void __iomem * __init xdbc_map_pci_mmio(u32 bus, u32 dev, u32 func) 40aeb9dd1dSLu Baolu { 41aeb9dd1dSLu Baolu u64 val64, sz64, mask64; 42aeb9dd1dSLu Baolu void __iomem *base; 43aeb9dd1dSLu Baolu u32 val, sz; 44aeb9dd1dSLu Baolu u8 byte; 45aeb9dd1dSLu Baolu 46aeb9dd1dSLu Baolu val = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0); 47aeb9dd1dSLu Baolu write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0, ~0); 48aeb9dd1dSLu Baolu sz = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0); 49aeb9dd1dSLu Baolu write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0, val); 50aeb9dd1dSLu Baolu 51aeb9dd1dSLu Baolu if (val == 0xffffffff || sz == 0xffffffff) { 52aeb9dd1dSLu Baolu pr_notice("invalid mmio bar\n"); 53aeb9dd1dSLu Baolu return NULL; 54aeb9dd1dSLu Baolu } 55aeb9dd1dSLu Baolu 56aeb9dd1dSLu Baolu val64 = val & PCI_BASE_ADDRESS_MEM_MASK; 57aeb9dd1dSLu Baolu sz64 = sz & PCI_BASE_ADDRESS_MEM_MASK; 58aeb9dd1dSLu Baolu mask64 = PCI_BASE_ADDRESS_MEM_MASK; 59aeb9dd1dSLu Baolu 60aeb9dd1dSLu Baolu if ((val & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) { 61aeb9dd1dSLu Baolu val = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4); 62aeb9dd1dSLu Baolu write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4, ~0); 63aeb9dd1dSLu Baolu sz = read_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4); 64aeb9dd1dSLu Baolu write_pci_config(bus, dev, func, PCI_BASE_ADDRESS_0 + 4, val); 65aeb9dd1dSLu Baolu 66aeb9dd1dSLu Baolu val64 |= (u64)val << 32; 67aeb9dd1dSLu Baolu sz64 |= (u64)sz << 32; 68aeb9dd1dSLu Baolu mask64 |= ~0ULL << 32; 69aeb9dd1dSLu Baolu } 70aeb9dd1dSLu Baolu 71aeb9dd1dSLu Baolu sz64 &= mask64; 72aeb9dd1dSLu Baolu 73aeb9dd1dSLu Baolu if (!sz64) { 74aeb9dd1dSLu Baolu pr_notice("invalid mmio address\n"); 75aeb9dd1dSLu Baolu return NULL; 76aeb9dd1dSLu Baolu } 77aeb9dd1dSLu Baolu 78aeb9dd1dSLu Baolu sz64 = 1ULL << __ffs64(sz64); 79aeb9dd1dSLu Baolu 80aeb9dd1dSLu Baolu /* Check if the mem space is enabled: */ 81aeb9dd1dSLu Baolu byte = read_pci_config_byte(bus, dev, func, PCI_COMMAND); 82aeb9dd1dSLu Baolu if (!(byte & PCI_COMMAND_MEMORY)) { 83aeb9dd1dSLu Baolu byte |= PCI_COMMAND_MEMORY; 84aeb9dd1dSLu Baolu write_pci_config_byte(bus, dev, func, PCI_COMMAND, byte); 85aeb9dd1dSLu Baolu } 86aeb9dd1dSLu Baolu 87aeb9dd1dSLu Baolu xdbc.xhci_start = val64; 88aeb9dd1dSLu Baolu xdbc.xhci_length = sz64; 89aeb9dd1dSLu Baolu base = early_ioremap(val64, sz64); 90aeb9dd1dSLu Baolu 91aeb9dd1dSLu Baolu return base; 92aeb9dd1dSLu Baolu } 93aeb9dd1dSLu Baolu 94aeb9dd1dSLu Baolu static void * __init xdbc_get_page(dma_addr_t *dma_addr) 95aeb9dd1dSLu Baolu { 96aeb9dd1dSLu Baolu void *virt; 97aeb9dd1dSLu Baolu 9826fb3daeSMike Rapoport virt = memblock_alloc(PAGE_SIZE, PAGE_SIZE); 99aeb9dd1dSLu Baolu if (!virt) 100aeb9dd1dSLu Baolu return NULL; 101aeb9dd1dSLu Baolu 102aeb9dd1dSLu Baolu if (dma_addr) 103aeb9dd1dSLu Baolu *dma_addr = (dma_addr_t)__pa(virt); 104aeb9dd1dSLu Baolu 105aeb9dd1dSLu Baolu return virt; 106aeb9dd1dSLu Baolu } 107aeb9dd1dSLu Baolu 108aeb9dd1dSLu Baolu static u32 __init xdbc_find_dbgp(int xdbc_num, u32 *b, u32 *d, u32 *f) 109aeb9dd1dSLu Baolu { 110aeb9dd1dSLu Baolu u32 bus, dev, func, class; 111aeb9dd1dSLu Baolu 112aeb9dd1dSLu Baolu for (bus = 0; bus < XDBC_PCI_MAX_BUSES; bus++) { 113aeb9dd1dSLu Baolu for (dev = 0; dev < XDBC_PCI_MAX_DEVICES; dev++) { 114aeb9dd1dSLu Baolu for (func = 0; func < XDBC_PCI_MAX_FUNCTION; func++) { 115aeb9dd1dSLu Baolu 116aeb9dd1dSLu Baolu class = read_pci_config(bus, dev, func, PCI_CLASS_REVISION); 117aeb9dd1dSLu Baolu if ((class >> 8) != PCI_CLASS_SERIAL_USB_XHCI) 118aeb9dd1dSLu Baolu continue; 119aeb9dd1dSLu Baolu 120aeb9dd1dSLu Baolu if (xdbc_num-- != 0) 121aeb9dd1dSLu Baolu continue; 122aeb9dd1dSLu Baolu 123aeb9dd1dSLu Baolu *b = bus; 124aeb9dd1dSLu Baolu *d = dev; 125aeb9dd1dSLu Baolu *f = func; 126aeb9dd1dSLu Baolu 127aeb9dd1dSLu Baolu return 0; 128aeb9dd1dSLu Baolu } 129aeb9dd1dSLu Baolu } 130aeb9dd1dSLu Baolu } 131aeb9dd1dSLu Baolu 132aeb9dd1dSLu Baolu return -1; 133aeb9dd1dSLu Baolu } 134aeb9dd1dSLu Baolu 135aeb9dd1dSLu Baolu static int handshake(void __iomem *ptr, u32 mask, u32 done, int wait, int delay) 136aeb9dd1dSLu Baolu { 137aeb9dd1dSLu Baolu u32 result; 138aeb9dd1dSLu Baolu 139796eed4bSChunfeng Yun return readl_poll_timeout_atomic(ptr, result, 140796eed4bSChunfeng Yun ((result & mask) == done), 141796eed4bSChunfeng Yun delay, wait); 142aeb9dd1dSLu Baolu } 143aeb9dd1dSLu Baolu 144aeb9dd1dSLu Baolu static void __init xdbc_bios_handoff(void) 145aeb9dd1dSLu Baolu { 146aeb9dd1dSLu Baolu int offset, timeout; 147aeb9dd1dSLu Baolu u32 val; 148aeb9dd1dSLu Baolu 149aeb9dd1dSLu Baolu offset = xhci_find_next_ext_cap(xdbc.xhci_base, 0, XHCI_EXT_CAPS_LEGACY); 150aeb9dd1dSLu Baolu val = readl(xdbc.xhci_base + offset); 151aeb9dd1dSLu Baolu 152aeb9dd1dSLu Baolu if (val & XHCI_HC_BIOS_OWNED) { 153aeb9dd1dSLu Baolu writel(val | XHCI_HC_OS_OWNED, xdbc.xhci_base + offset); 154aeb9dd1dSLu Baolu timeout = handshake(xdbc.xhci_base + offset, XHCI_HC_BIOS_OWNED, 0, 5000, 10); 155aeb9dd1dSLu Baolu 156aeb9dd1dSLu Baolu if (timeout) { 157aeb9dd1dSLu Baolu pr_notice("failed to hand over xHCI control from BIOS\n"); 158aeb9dd1dSLu Baolu writel(val & ~XHCI_HC_BIOS_OWNED, xdbc.xhci_base + offset); 159aeb9dd1dSLu Baolu } 160aeb9dd1dSLu Baolu } 161aeb9dd1dSLu Baolu 162aeb9dd1dSLu Baolu /* Disable BIOS SMIs and clear all SMI events: */ 163aeb9dd1dSLu Baolu val = readl(xdbc.xhci_base + offset + XHCI_LEGACY_CONTROL_OFFSET); 164aeb9dd1dSLu Baolu val &= XHCI_LEGACY_DISABLE_SMI; 165aeb9dd1dSLu Baolu val |= XHCI_LEGACY_SMI_EVENTS; 166aeb9dd1dSLu Baolu writel(val, xdbc.xhci_base + offset + XHCI_LEGACY_CONTROL_OFFSET); 167aeb9dd1dSLu Baolu } 168aeb9dd1dSLu Baolu 169aeb9dd1dSLu Baolu static int __init 170aeb9dd1dSLu Baolu xdbc_alloc_ring(struct xdbc_segment *seg, struct xdbc_ring *ring) 171aeb9dd1dSLu Baolu { 172aeb9dd1dSLu Baolu seg->trbs = xdbc_get_page(&seg->dma); 173aeb9dd1dSLu Baolu if (!seg->trbs) 174aeb9dd1dSLu Baolu return -ENOMEM; 175aeb9dd1dSLu Baolu 176aeb9dd1dSLu Baolu ring->segment = seg; 177aeb9dd1dSLu Baolu 178aeb9dd1dSLu Baolu return 0; 179aeb9dd1dSLu Baolu } 180aeb9dd1dSLu Baolu 181aeb9dd1dSLu Baolu static void __init xdbc_free_ring(struct xdbc_ring *ring) 182aeb9dd1dSLu Baolu { 183aeb9dd1dSLu Baolu struct xdbc_segment *seg = ring->segment; 184aeb9dd1dSLu Baolu 185aeb9dd1dSLu Baolu if (!seg) 186aeb9dd1dSLu Baolu return; 187aeb9dd1dSLu Baolu 188*3ecc6834SMike Rapoport memblock_phys_free(seg->dma, PAGE_SIZE); 189aeb9dd1dSLu Baolu ring->segment = NULL; 190aeb9dd1dSLu Baolu } 191aeb9dd1dSLu Baolu 192aeb9dd1dSLu Baolu static void xdbc_reset_ring(struct xdbc_ring *ring) 193aeb9dd1dSLu Baolu { 194aeb9dd1dSLu Baolu struct xdbc_segment *seg = ring->segment; 195aeb9dd1dSLu Baolu struct xdbc_trb *link_trb; 196aeb9dd1dSLu Baolu 197aeb9dd1dSLu Baolu memset(seg->trbs, 0, PAGE_SIZE); 198aeb9dd1dSLu Baolu 199aeb9dd1dSLu Baolu ring->enqueue = seg->trbs; 200aeb9dd1dSLu Baolu ring->dequeue = seg->trbs; 201aeb9dd1dSLu Baolu ring->cycle_state = 1; 202aeb9dd1dSLu Baolu 203aeb9dd1dSLu Baolu if (ring != &xdbc.evt_ring) { 204aeb9dd1dSLu Baolu link_trb = &seg->trbs[XDBC_TRBS_PER_SEGMENT - 1]; 205aeb9dd1dSLu Baolu link_trb->field[0] = cpu_to_le32(lower_32_bits(seg->dma)); 206aeb9dd1dSLu Baolu link_trb->field[1] = cpu_to_le32(upper_32_bits(seg->dma)); 207aeb9dd1dSLu Baolu link_trb->field[3] = cpu_to_le32(TRB_TYPE(TRB_LINK)) | cpu_to_le32(LINK_TOGGLE); 208aeb9dd1dSLu Baolu } 209aeb9dd1dSLu Baolu } 210aeb9dd1dSLu Baolu 211aeb9dd1dSLu Baolu static inline void xdbc_put_utf16(u16 *s, const char *c, size_t size) 212aeb9dd1dSLu Baolu { 213aeb9dd1dSLu Baolu int i; 214aeb9dd1dSLu Baolu 215aeb9dd1dSLu Baolu for (i = 0; i < size; i++) 216aeb9dd1dSLu Baolu s[i] = cpu_to_le16(c[i]); 217aeb9dd1dSLu Baolu } 218aeb9dd1dSLu Baolu 219aeb9dd1dSLu Baolu static void xdbc_mem_init(void) 220aeb9dd1dSLu Baolu { 221aeb9dd1dSLu Baolu struct xdbc_ep_context *ep_in, *ep_out; 222aeb9dd1dSLu Baolu struct usb_string_descriptor *s_desc; 223aeb9dd1dSLu Baolu struct xdbc_erst_entry *entry; 224aeb9dd1dSLu Baolu struct xdbc_strings *strings; 225aeb9dd1dSLu Baolu struct xdbc_context *ctx; 226aeb9dd1dSLu Baolu unsigned int max_burst; 227aeb9dd1dSLu Baolu u32 string_length; 228aeb9dd1dSLu Baolu int index = 0; 229aeb9dd1dSLu Baolu u32 dev_info; 230aeb9dd1dSLu Baolu 231aeb9dd1dSLu Baolu xdbc_reset_ring(&xdbc.evt_ring); 232aeb9dd1dSLu Baolu xdbc_reset_ring(&xdbc.in_ring); 233aeb9dd1dSLu Baolu xdbc_reset_ring(&xdbc.out_ring); 234aeb9dd1dSLu Baolu memset(xdbc.table_base, 0, PAGE_SIZE); 235aeb9dd1dSLu Baolu memset(xdbc.out_buf, 0, PAGE_SIZE); 236aeb9dd1dSLu Baolu 237aeb9dd1dSLu Baolu /* Initialize event ring segment table: */ 238aeb9dd1dSLu Baolu xdbc.erst_size = 16; 239aeb9dd1dSLu Baolu xdbc.erst_base = xdbc.table_base + index * XDBC_TABLE_ENTRY_SIZE; 240aeb9dd1dSLu Baolu xdbc.erst_dma = xdbc.table_dma + index * XDBC_TABLE_ENTRY_SIZE; 241aeb9dd1dSLu Baolu 242aeb9dd1dSLu Baolu index += XDBC_ERST_ENTRY_NUM; 243aeb9dd1dSLu Baolu entry = (struct xdbc_erst_entry *)xdbc.erst_base; 244aeb9dd1dSLu Baolu 245aeb9dd1dSLu Baolu entry->seg_addr = cpu_to_le64(xdbc.evt_seg.dma); 246aeb9dd1dSLu Baolu entry->seg_size = cpu_to_le32(XDBC_TRBS_PER_SEGMENT); 247aeb9dd1dSLu Baolu entry->__reserved_0 = 0; 248aeb9dd1dSLu Baolu 249aeb9dd1dSLu Baolu /* Initialize ERST registers: */ 250aeb9dd1dSLu Baolu writel(1, &xdbc.xdbc_reg->ersts); 251aeb9dd1dSLu Baolu xdbc_write64(xdbc.erst_dma, &xdbc.xdbc_reg->erstba); 252aeb9dd1dSLu Baolu xdbc_write64(xdbc.evt_seg.dma, &xdbc.xdbc_reg->erdp); 253aeb9dd1dSLu Baolu 254aeb9dd1dSLu Baolu /* Debug capability contexts: */ 255aeb9dd1dSLu Baolu xdbc.dbcc_size = 64 * 3; 256aeb9dd1dSLu Baolu xdbc.dbcc_base = xdbc.table_base + index * XDBC_TABLE_ENTRY_SIZE; 257aeb9dd1dSLu Baolu xdbc.dbcc_dma = xdbc.table_dma + index * XDBC_TABLE_ENTRY_SIZE; 258aeb9dd1dSLu Baolu 259aeb9dd1dSLu Baolu index += XDBC_DBCC_ENTRY_NUM; 260aeb9dd1dSLu Baolu 261aeb9dd1dSLu Baolu /* Popluate the strings: */ 262aeb9dd1dSLu Baolu xdbc.string_size = sizeof(struct xdbc_strings); 263aeb9dd1dSLu Baolu xdbc.string_base = xdbc.table_base + index * XDBC_TABLE_ENTRY_SIZE; 264aeb9dd1dSLu Baolu xdbc.string_dma = xdbc.table_dma + index * XDBC_TABLE_ENTRY_SIZE; 265aeb9dd1dSLu Baolu strings = (struct xdbc_strings *)xdbc.string_base; 266aeb9dd1dSLu Baolu 267aeb9dd1dSLu Baolu index += XDBC_STRING_ENTRY_NUM; 268aeb9dd1dSLu Baolu 269aeb9dd1dSLu Baolu /* Serial string: */ 270aeb9dd1dSLu Baolu s_desc = (struct usb_string_descriptor *)strings->serial; 271aeb9dd1dSLu Baolu s_desc->bLength = (strlen(XDBC_STRING_SERIAL) + 1) * 2; 272aeb9dd1dSLu Baolu s_desc->bDescriptorType = USB_DT_STRING; 273aeb9dd1dSLu Baolu 274aeb9dd1dSLu Baolu xdbc_put_utf16(s_desc->wData, XDBC_STRING_SERIAL, strlen(XDBC_STRING_SERIAL)); 275aeb9dd1dSLu Baolu string_length = s_desc->bLength; 276aeb9dd1dSLu Baolu string_length <<= 8; 277aeb9dd1dSLu Baolu 278aeb9dd1dSLu Baolu /* Product string: */ 279aeb9dd1dSLu Baolu s_desc = (struct usb_string_descriptor *)strings->product; 280aeb9dd1dSLu Baolu s_desc->bLength = (strlen(XDBC_STRING_PRODUCT) + 1) * 2; 281aeb9dd1dSLu Baolu s_desc->bDescriptorType = USB_DT_STRING; 282aeb9dd1dSLu Baolu 283aeb9dd1dSLu Baolu xdbc_put_utf16(s_desc->wData, XDBC_STRING_PRODUCT, strlen(XDBC_STRING_PRODUCT)); 284aeb9dd1dSLu Baolu string_length += s_desc->bLength; 285aeb9dd1dSLu Baolu string_length <<= 8; 286aeb9dd1dSLu Baolu 287aeb9dd1dSLu Baolu /* Manufacture string: */ 288aeb9dd1dSLu Baolu s_desc = (struct usb_string_descriptor *)strings->manufacturer; 289aeb9dd1dSLu Baolu s_desc->bLength = (strlen(XDBC_STRING_MANUFACTURER) + 1) * 2; 290aeb9dd1dSLu Baolu s_desc->bDescriptorType = USB_DT_STRING; 291aeb9dd1dSLu Baolu 292aeb9dd1dSLu Baolu xdbc_put_utf16(s_desc->wData, XDBC_STRING_MANUFACTURER, strlen(XDBC_STRING_MANUFACTURER)); 293aeb9dd1dSLu Baolu string_length += s_desc->bLength; 294aeb9dd1dSLu Baolu string_length <<= 8; 295aeb9dd1dSLu Baolu 296aeb9dd1dSLu Baolu /* String0: */ 297aeb9dd1dSLu Baolu strings->string0[0] = 4; 298aeb9dd1dSLu Baolu strings->string0[1] = USB_DT_STRING; 299aeb9dd1dSLu Baolu strings->string0[2] = 0x09; 300aeb9dd1dSLu Baolu strings->string0[3] = 0x04; 301aeb9dd1dSLu Baolu 302aeb9dd1dSLu Baolu string_length += 4; 303aeb9dd1dSLu Baolu 304aeb9dd1dSLu Baolu /* Populate info Context: */ 305aeb9dd1dSLu Baolu ctx = (struct xdbc_context *)xdbc.dbcc_base; 306aeb9dd1dSLu Baolu 307aeb9dd1dSLu Baolu ctx->info.string0 = cpu_to_le64(xdbc.string_dma); 308aeb9dd1dSLu Baolu ctx->info.manufacturer = cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH); 309aeb9dd1dSLu Baolu ctx->info.product = cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH * 2); 310aeb9dd1dSLu Baolu ctx->info.serial = cpu_to_le64(xdbc.string_dma + XDBC_MAX_STRING_LENGTH * 3); 311aeb9dd1dSLu Baolu ctx->info.length = cpu_to_le32(string_length); 312aeb9dd1dSLu Baolu 313aeb9dd1dSLu Baolu /* Populate bulk out endpoint context: */ 314aeb9dd1dSLu Baolu max_burst = DEBUG_MAX_BURST(readl(&xdbc.xdbc_reg->control)); 315aeb9dd1dSLu Baolu ep_out = (struct xdbc_ep_context *)&ctx->out; 316aeb9dd1dSLu Baolu 317aeb9dd1dSLu Baolu ep_out->ep_info1 = 0; 318aeb9dd1dSLu Baolu ep_out->ep_info2 = cpu_to_le32(EP_TYPE(BULK_OUT_EP) | MAX_PACKET(1024) | MAX_BURST(max_burst)); 319aeb9dd1dSLu Baolu ep_out->deq = cpu_to_le64(xdbc.out_seg.dma | xdbc.out_ring.cycle_state); 320aeb9dd1dSLu Baolu 321aeb9dd1dSLu Baolu /* Populate bulk in endpoint context: */ 322aeb9dd1dSLu Baolu ep_in = (struct xdbc_ep_context *)&ctx->in; 323aeb9dd1dSLu Baolu 324aeb9dd1dSLu Baolu ep_in->ep_info1 = 0; 3254bda35a0SLu Baolu ep_in->ep_info2 = cpu_to_le32(EP_TYPE(BULK_IN_EP) | MAX_PACKET(1024) | MAX_BURST(max_burst)); 326aeb9dd1dSLu Baolu ep_in->deq = cpu_to_le64(xdbc.in_seg.dma | xdbc.in_ring.cycle_state); 327aeb9dd1dSLu Baolu 328aeb9dd1dSLu Baolu /* Set DbC context and info registers: */ 329aeb9dd1dSLu Baolu xdbc_write64(xdbc.dbcc_dma, &xdbc.xdbc_reg->dccp); 330aeb9dd1dSLu Baolu 331aeb9dd1dSLu Baolu dev_info = cpu_to_le32((XDBC_VENDOR_ID << 16) | XDBC_PROTOCOL); 332aeb9dd1dSLu Baolu writel(dev_info, &xdbc.xdbc_reg->devinfo1); 333aeb9dd1dSLu Baolu 334aeb9dd1dSLu Baolu dev_info = cpu_to_le32((XDBC_DEVICE_REV << 16) | XDBC_PRODUCT_ID); 335aeb9dd1dSLu Baolu writel(dev_info, &xdbc.xdbc_reg->devinfo2); 336aeb9dd1dSLu Baolu 337aeb9dd1dSLu Baolu xdbc.in_buf = xdbc.out_buf + XDBC_MAX_PACKET; 338aeb9dd1dSLu Baolu xdbc.in_dma = xdbc.out_dma + XDBC_MAX_PACKET; 339aeb9dd1dSLu Baolu } 340aeb9dd1dSLu Baolu 341aeb9dd1dSLu Baolu static void xdbc_do_reset_debug_port(u32 id, u32 count) 342aeb9dd1dSLu Baolu { 343aeb9dd1dSLu Baolu void __iomem *ops_reg; 344aeb9dd1dSLu Baolu void __iomem *portsc; 345aeb9dd1dSLu Baolu u32 val, cap_length; 346aeb9dd1dSLu Baolu int i; 347aeb9dd1dSLu Baolu 348aeb9dd1dSLu Baolu cap_length = readl(xdbc.xhci_base) & 0xff; 349aeb9dd1dSLu Baolu ops_reg = xdbc.xhci_base + cap_length; 350aeb9dd1dSLu Baolu 351aeb9dd1dSLu Baolu id--; 352aeb9dd1dSLu Baolu for (i = id; i < (id + count); i++) { 353aeb9dd1dSLu Baolu portsc = ops_reg + 0x400 + i * 0x10; 354aeb9dd1dSLu Baolu val = readl(portsc); 355aeb9dd1dSLu Baolu if (!(val & PORT_CONNECT)) 356aeb9dd1dSLu Baolu writel(val | PORT_RESET, portsc); 357aeb9dd1dSLu Baolu } 358aeb9dd1dSLu Baolu } 359aeb9dd1dSLu Baolu 360aeb9dd1dSLu Baolu static void xdbc_reset_debug_port(void) 361aeb9dd1dSLu Baolu { 362aeb9dd1dSLu Baolu u32 val, port_offset, port_count; 363aeb9dd1dSLu Baolu int offset = 0; 364aeb9dd1dSLu Baolu 365aeb9dd1dSLu Baolu do { 366aeb9dd1dSLu Baolu offset = xhci_find_next_ext_cap(xdbc.xhci_base, offset, XHCI_EXT_CAPS_PROTOCOL); 367aeb9dd1dSLu Baolu if (!offset) 368aeb9dd1dSLu Baolu break; 369aeb9dd1dSLu Baolu 370aeb9dd1dSLu Baolu val = readl(xdbc.xhci_base + offset); 371aeb9dd1dSLu Baolu if (XHCI_EXT_PORT_MAJOR(val) != 0x3) 372aeb9dd1dSLu Baolu continue; 373aeb9dd1dSLu Baolu 374aeb9dd1dSLu Baolu val = readl(xdbc.xhci_base + offset + 8); 375aeb9dd1dSLu Baolu port_offset = XHCI_EXT_PORT_OFF(val); 376aeb9dd1dSLu Baolu port_count = XHCI_EXT_PORT_COUNT(val); 377aeb9dd1dSLu Baolu 378aeb9dd1dSLu Baolu xdbc_do_reset_debug_port(port_offset, port_count); 379aeb9dd1dSLu Baolu } while (1); 380aeb9dd1dSLu Baolu } 381aeb9dd1dSLu Baolu 382aeb9dd1dSLu Baolu static void 383aeb9dd1dSLu Baolu xdbc_queue_trb(struct xdbc_ring *ring, u32 field1, u32 field2, u32 field3, u32 field4) 384aeb9dd1dSLu Baolu { 385aeb9dd1dSLu Baolu struct xdbc_trb *trb, *link_trb; 386aeb9dd1dSLu Baolu 387aeb9dd1dSLu Baolu trb = ring->enqueue; 388aeb9dd1dSLu Baolu trb->field[0] = cpu_to_le32(field1); 389aeb9dd1dSLu Baolu trb->field[1] = cpu_to_le32(field2); 390aeb9dd1dSLu Baolu trb->field[2] = cpu_to_le32(field3); 391aeb9dd1dSLu Baolu trb->field[3] = cpu_to_le32(field4); 392aeb9dd1dSLu Baolu 393aeb9dd1dSLu Baolu ++(ring->enqueue); 394aeb9dd1dSLu Baolu if (ring->enqueue >= &ring->segment->trbs[TRBS_PER_SEGMENT - 1]) { 395aeb9dd1dSLu Baolu link_trb = ring->enqueue; 396aeb9dd1dSLu Baolu if (ring->cycle_state) 397aeb9dd1dSLu Baolu link_trb->field[3] |= cpu_to_le32(TRB_CYCLE); 398aeb9dd1dSLu Baolu else 399aeb9dd1dSLu Baolu link_trb->field[3] &= cpu_to_le32(~TRB_CYCLE); 400aeb9dd1dSLu Baolu 401aeb9dd1dSLu Baolu ring->enqueue = ring->segment->trbs; 402aeb9dd1dSLu Baolu ring->cycle_state ^= 1; 403aeb9dd1dSLu Baolu } 404aeb9dd1dSLu Baolu } 405aeb9dd1dSLu Baolu 406aeb9dd1dSLu Baolu static void xdbc_ring_doorbell(int target) 407aeb9dd1dSLu Baolu { 408aeb9dd1dSLu Baolu writel(DOOR_BELL_TARGET(target), &xdbc.xdbc_reg->doorbell); 409aeb9dd1dSLu Baolu } 410aeb9dd1dSLu Baolu 411aeb9dd1dSLu Baolu static int xdbc_start(void) 412aeb9dd1dSLu Baolu { 413aeb9dd1dSLu Baolu u32 ctrl, status; 414aeb9dd1dSLu Baolu int ret; 415aeb9dd1dSLu Baolu 416aeb9dd1dSLu Baolu ctrl = readl(&xdbc.xdbc_reg->control); 417aeb9dd1dSLu Baolu writel(ctrl | CTRL_DBC_ENABLE | CTRL_PORT_ENABLE, &xdbc.xdbc_reg->control); 418aeb9dd1dSLu Baolu ret = handshake(&xdbc.xdbc_reg->control, CTRL_DBC_ENABLE, CTRL_DBC_ENABLE, 100000, 100); 419aeb9dd1dSLu Baolu if (ret) { 420aeb9dd1dSLu Baolu xdbc_trace("failed to initialize hardware\n"); 421aeb9dd1dSLu Baolu return ret; 422aeb9dd1dSLu Baolu } 423aeb9dd1dSLu Baolu 424aeb9dd1dSLu Baolu /* Reset port to avoid bus hang: */ 425aeb9dd1dSLu Baolu if (xdbc.vendor == PCI_VENDOR_ID_INTEL) 426aeb9dd1dSLu Baolu xdbc_reset_debug_port(); 427aeb9dd1dSLu Baolu 428aeb9dd1dSLu Baolu /* Wait for port connection: */ 429aeb9dd1dSLu Baolu ret = handshake(&xdbc.xdbc_reg->portsc, PORTSC_CONN_STATUS, PORTSC_CONN_STATUS, 5000000, 100); 430aeb9dd1dSLu Baolu if (ret) { 431aeb9dd1dSLu Baolu xdbc_trace("waiting for connection timed out\n"); 432aeb9dd1dSLu Baolu return ret; 433aeb9dd1dSLu Baolu } 434aeb9dd1dSLu Baolu 435aeb9dd1dSLu Baolu /* Wait for debug device to be configured: */ 436aeb9dd1dSLu Baolu ret = handshake(&xdbc.xdbc_reg->control, CTRL_DBC_RUN, CTRL_DBC_RUN, 5000000, 100); 437aeb9dd1dSLu Baolu if (ret) { 438aeb9dd1dSLu Baolu xdbc_trace("waiting for device configuration timed out\n"); 439aeb9dd1dSLu Baolu return ret; 440aeb9dd1dSLu Baolu } 441aeb9dd1dSLu Baolu 442aeb9dd1dSLu Baolu /* Check port number: */ 443aeb9dd1dSLu Baolu status = readl(&xdbc.xdbc_reg->status); 444aeb9dd1dSLu Baolu if (!DCST_DEBUG_PORT(status)) { 445aeb9dd1dSLu Baolu xdbc_trace("invalid root hub port number\n"); 446aeb9dd1dSLu Baolu return -ENODEV; 447aeb9dd1dSLu Baolu } 448aeb9dd1dSLu Baolu 449aeb9dd1dSLu Baolu xdbc.port_number = DCST_DEBUG_PORT(status); 450aeb9dd1dSLu Baolu 451aeb9dd1dSLu Baolu xdbc_trace("DbC is running now, control 0x%08x port ID %d\n", 452aeb9dd1dSLu Baolu readl(&xdbc.xdbc_reg->control), xdbc.port_number); 453aeb9dd1dSLu Baolu 454aeb9dd1dSLu Baolu return 0; 455aeb9dd1dSLu Baolu } 456aeb9dd1dSLu Baolu 457aeb9dd1dSLu Baolu static int xdbc_bulk_transfer(void *data, int size, bool read) 458aeb9dd1dSLu Baolu { 459aeb9dd1dSLu Baolu struct xdbc_ring *ring; 460aeb9dd1dSLu Baolu struct xdbc_trb *trb; 461aeb9dd1dSLu Baolu u32 length, control; 462aeb9dd1dSLu Baolu u32 cycle; 463aeb9dd1dSLu Baolu u64 addr; 464aeb9dd1dSLu Baolu 465aeb9dd1dSLu Baolu if (size > XDBC_MAX_PACKET) { 466aeb9dd1dSLu Baolu xdbc_trace("bad parameter, size %d\n", size); 467aeb9dd1dSLu Baolu return -EINVAL; 468aeb9dd1dSLu Baolu } 469aeb9dd1dSLu Baolu 470aeb9dd1dSLu Baolu if (!(xdbc.flags & XDBC_FLAGS_INITIALIZED) || 471aeb9dd1dSLu Baolu !(xdbc.flags & XDBC_FLAGS_CONFIGURED) || 472aeb9dd1dSLu Baolu (!read && (xdbc.flags & XDBC_FLAGS_OUT_STALL)) || 473aeb9dd1dSLu Baolu (read && (xdbc.flags & XDBC_FLAGS_IN_STALL))) { 474aeb9dd1dSLu Baolu 475aeb9dd1dSLu Baolu xdbc_trace("connection not ready, flags %08x\n", xdbc.flags); 476aeb9dd1dSLu Baolu return -EIO; 477aeb9dd1dSLu Baolu } 478aeb9dd1dSLu Baolu 479aeb9dd1dSLu Baolu ring = (read ? &xdbc.in_ring : &xdbc.out_ring); 480aeb9dd1dSLu Baolu trb = ring->enqueue; 481aeb9dd1dSLu Baolu cycle = ring->cycle_state; 482aeb9dd1dSLu Baolu length = TRB_LEN(size); 483aeb9dd1dSLu Baolu control = TRB_TYPE(TRB_NORMAL) | TRB_IOC; 484aeb9dd1dSLu Baolu 485aeb9dd1dSLu Baolu if (cycle) 486aeb9dd1dSLu Baolu control &= cpu_to_le32(~TRB_CYCLE); 487aeb9dd1dSLu Baolu else 488aeb9dd1dSLu Baolu control |= cpu_to_le32(TRB_CYCLE); 489aeb9dd1dSLu Baolu 490aeb9dd1dSLu Baolu if (read) { 491aeb9dd1dSLu Baolu memset(xdbc.in_buf, 0, XDBC_MAX_PACKET); 492aeb9dd1dSLu Baolu addr = xdbc.in_dma; 493aeb9dd1dSLu Baolu xdbc.flags |= XDBC_FLAGS_IN_PROCESS; 494aeb9dd1dSLu Baolu } else { 495aeb9dd1dSLu Baolu memset(xdbc.out_buf, 0, XDBC_MAX_PACKET); 496aeb9dd1dSLu Baolu memcpy(xdbc.out_buf, data, size); 497aeb9dd1dSLu Baolu addr = xdbc.out_dma; 498aeb9dd1dSLu Baolu xdbc.flags |= XDBC_FLAGS_OUT_PROCESS; 499aeb9dd1dSLu Baolu } 500aeb9dd1dSLu Baolu 501aeb9dd1dSLu Baolu xdbc_queue_trb(ring, lower_32_bits(addr), upper_32_bits(addr), length, control); 502aeb9dd1dSLu Baolu 503aeb9dd1dSLu Baolu /* 504aeb9dd1dSLu Baolu * Add a barrier between writes of trb fields and flipping 505aeb9dd1dSLu Baolu * the cycle bit: 506aeb9dd1dSLu Baolu */ 507aeb9dd1dSLu Baolu wmb(); 508aeb9dd1dSLu Baolu if (cycle) 509aeb9dd1dSLu Baolu trb->field[3] |= cpu_to_le32(cycle); 510aeb9dd1dSLu Baolu else 511aeb9dd1dSLu Baolu trb->field[3] &= cpu_to_le32(~TRB_CYCLE); 512aeb9dd1dSLu Baolu 513aeb9dd1dSLu Baolu xdbc_ring_doorbell(read ? IN_EP_DOORBELL : OUT_EP_DOORBELL); 514aeb9dd1dSLu Baolu 515aeb9dd1dSLu Baolu return size; 516aeb9dd1dSLu Baolu } 517aeb9dd1dSLu Baolu 518aeb9dd1dSLu Baolu static int xdbc_handle_external_reset(void) 519aeb9dd1dSLu Baolu { 520aeb9dd1dSLu Baolu int ret = 0; 521aeb9dd1dSLu Baolu 522aeb9dd1dSLu Baolu xdbc.flags = 0; 523aeb9dd1dSLu Baolu writel(0, &xdbc.xdbc_reg->control); 524aeb9dd1dSLu Baolu ret = handshake(&xdbc.xdbc_reg->control, CTRL_DBC_ENABLE, 0, 100000, 10); 525aeb9dd1dSLu Baolu if (ret) 526aeb9dd1dSLu Baolu goto reset_out; 527aeb9dd1dSLu Baolu 528aeb9dd1dSLu Baolu xdbc_mem_init(); 529aeb9dd1dSLu Baolu 530aeb9dd1dSLu Baolu ret = xdbc_start(); 531aeb9dd1dSLu Baolu if (ret < 0) 532aeb9dd1dSLu Baolu goto reset_out; 533aeb9dd1dSLu Baolu 534aeb9dd1dSLu Baolu xdbc_trace("dbc recovered\n"); 535aeb9dd1dSLu Baolu 536aeb9dd1dSLu Baolu xdbc.flags |= XDBC_FLAGS_INITIALIZED | XDBC_FLAGS_CONFIGURED; 537aeb9dd1dSLu Baolu 538aeb9dd1dSLu Baolu xdbc_bulk_transfer(NULL, XDBC_MAX_PACKET, true); 539aeb9dd1dSLu Baolu 540aeb9dd1dSLu Baolu return 0; 541aeb9dd1dSLu Baolu 542aeb9dd1dSLu Baolu reset_out: 543aeb9dd1dSLu Baolu xdbc_trace("failed to recover from external reset\n"); 544aeb9dd1dSLu Baolu return ret; 545aeb9dd1dSLu Baolu } 546aeb9dd1dSLu Baolu 547aeb9dd1dSLu Baolu static int __init xdbc_early_setup(void) 548aeb9dd1dSLu Baolu { 549aeb9dd1dSLu Baolu int ret; 550aeb9dd1dSLu Baolu 551aeb9dd1dSLu Baolu writel(0, &xdbc.xdbc_reg->control); 552aeb9dd1dSLu Baolu ret = handshake(&xdbc.xdbc_reg->control, CTRL_DBC_ENABLE, 0, 100000, 100); 553aeb9dd1dSLu Baolu if (ret) 554aeb9dd1dSLu Baolu return ret; 555aeb9dd1dSLu Baolu 556aeb9dd1dSLu Baolu /* Allocate the table page: */ 557aeb9dd1dSLu Baolu xdbc.table_base = xdbc_get_page(&xdbc.table_dma); 558aeb9dd1dSLu Baolu if (!xdbc.table_base) 559aeb9dd1dSLu Baolu return -ENOMEM; 560aeb9dd1dSLu Baolu 561aeb9dd1dSLu Baolu /* Get and store the transfer buffer: */ 562aeb9dd1dSLu Baolu xdbc.out_buf = xdbc_get_page(&xdbc.out_dma); 563aeb9dd1dSLu Baolu if (!xdbc.out_buf) 564aeb9dd1dSLu Baolu return -ENOMEM; 565aeb9dd1dSLu Baolu 566aeb9dd1dSLu Baolu /* Allocate the event ring: */ 567aeb9dd1dSLu Baolu ret = xdbc_alloc_ring(&xdbc.evt_seg, &xdbc.evt_ring); 568aeb9dd1dSLu Baolu if (ret < 0) 569aeb9dd1dSLu Baolu return ret; 570aeb9dd1dSLu Baolu 571aeb9dd1dSLu Baolu /* Allocate IN/OUT endpoint transfer rings: */ 572aeb9dd1dSLu Baolu ret = xdbc_alloc_ring(&xdbc.in_seg, &xdbc.in_ring); 573aeb9dd1dSLu Baolu if (ret < 0) 574aeb9dd1dSLu Baolu return ret; 575aeb9dd1dSLu Baolu 576aeb9dd1dSLu Baolu ret = xdbc_alloc_ring(&xdbc.out_seg, &xdbc.out_ring); 577aeb9dd1dSLu Baolu if (ret < 0) 578aeb9dd1dSLu Baolu return ret; 579aeb9dd1dSLu Baolu 580aeb9dd1dSLu Baolu xdbc_mem_init(); 581aeb9dd1dSLu Baolu 582aeb9dd1dSLu Baolu ret = xdbc_start(); 583aeb9dd1dSLu Baolu if (ret < 0) { 584aeb9dd1dSLu Baolu writel(0, &xdbc.xdbc_reg->control); 585aeb9dd1dSLu Baolu return ret; 586aeb9dd1dSLu Baolu } 587aeb9dd1dSLu Baolu 588aeb9dd1dSLu Baolu xdbc.flags |= XDBC_FLAGS_INITIALIZED | XDBC_FLAGS_CONFIGURED; 589aeb9dd1dSLu Baolu 590aeb9dd1dSLu Baolu xdbc_bulk_transfer(NULL, XDBC_MAX_PACKET, true); 591aeb9dd1dSLu Baolu 592aeb9dd1dSLu Baolu return 0; 593aeb9dd1dSLu Baolu } 594aeb9dd1dSLu Baolu 595aeb9dd1dSLu Baolu int __init early_xdbc_parse_parameter(char *s) 596aeb9dd1dSLu Baolu { 597aeb9dd1dSLu Baolu unsigned long dbgp_num = 0; 598aeb9dd1dSLu Baolu u32 bus, dev, func, offset; 599aeb9dd1dSLu Baolu int ret; 600aeb9dd1dSLu Baolu 601aeb9dd1dSLu Baolu if (!early_pci_allowed()) 602aeb9dd1dSLu Baolu return -EPERM; 603aeb9dd1dSLu Baolu 604aeb9dd1dSLu Baolu if (strstr(s, "keep")) 605aeb9dd1dSLu Baolu early_console_keep = true; 606aeb9dd1dSLu Baolu 607aeb9dd1dSLu Baolu if (xdbc.xdbc_reg) 608aeb9dd1dSLu Baolu return 0; 609aeb9dd1dSLu Baolu 610aeb9dd1dSLu Baolu if (*s && kstrtoul(s, 0, &dbgp_num)) 611aeb9dd1dSLu Baolu dbgp_num = 0; 612aeb9dd1dSLu Baolu 613aeb9dd1dSLu Baolu pr_notice("dbgp_num: %lu\n", dbgp_num); 614aeb9dd1dSLu Baolu 615aeb9dd1dSLu Baolu /* Locate the host controller: */ 616aeb9dd1dSLu Baolu ret = xdbc_find_dbgp(dbgp_num, &bus, &dev, &func); 617aeb9dd1dSLu Baolu if (ret) { 618aeb9dd1dSLu Baolu pr_notice("failed to locate xhci host\n"); 619aeb9dd1dSLu Baolu return -ENODEV; 620aeb9dd1dSLu Baolu } 621aeb9dd1dSLu Baolu 622aeb9dd1dSLu Baolu xdbc.vendor = read_pci_config_16(bus, dev, func, PCI_VENDOR_ID); 623aeb9dd1dSLu Baolu xdbc.device = read_pci_config_16(bus, dev, func, PCI_DEVICE_ID); 624aeb9dd1dSLu Baolu xdbc.bus = bus; 625aeb9dd1dSLu Baolu xdbc.dev = dev; 626aeb9dd1dSLu Baolu xdbc.func = func; 627aeb9dd1dSLu Baolu 628aeb9dd1dSLu Baolu /* Map the IO memory: */ 629aeb9dd1dSLu Baolu xdbc.xhci_base = xdbc_map_pci_mmio(bus, dev, func); 630aeb9dd1dSLu Baolu if (!xdbc.xhci_base) 631aeb9dd1dSLu Baolu return -EINVAL; 632aeb9dd1dSLu Baolu 633aeb9dd1dSLu Baolu /* Locate DbC registers: */ 634aeb9dd1dSLu Baolu offset = xhci_find_next_ext_cap(xdbc.xhci_base, 0, XHCI_EXT_CAPS_DEBUG); 635aeb9dd1dSLu Baolu if (!offset) { 636aeb9dd1dSLu Baolu pr_notice("xhci host doesn't support debug capability\n"); 637aeb9dd1dSLu Baolu early_iounmap(xdbc.xhci_base, xdbc.xhci_length); 638aeb9dd1dSLu Baolu xdbc.xhci_base = NULL; 639aeb9dd1dSLu Baolu xdbc.xhci_length = 0; 640aeb9dd1dSLu Baolu 641aeb9dd1dSLu Baolu return -ENODEV; 642aeb9dd1dSLu Baolu } 643aeb9dd1dSLu Baolu xdbc.xdbc_reg = (struct xdbc_regs __iomem *)(xdbc.xhci_base + offset); 644aeb9dd1dSLu Baolu 645aeb9dd1dSLu Baolu return 0; 646aeb9dd1dSLu Baolu } 647aeb9dd1dSLu Baolu 648aeb9dd1dSLu Baolu int __init early_xdbc_setup_hardware(void) 649aeb9dd1dSLu Baolu { 650aeb9dd1dSLu Baolu int ret; 651aeb9dd1dSLu Baolu 652aeb9dd1dSLu Baolu if (!xdbc.xdbc_reg) 653aeb9dd1dSLu Baolu return -ENODEV; 654aeb9dd1dSLu Baolu 655aeb9dd1dSLu Baolu xdbc_bios_handoff(); 656aeb9dd1dSLu Baolu 657aeb9dd1dSLu Baolu raw_spin_lock_init(&xdbc.lock); 658aeb9dd1dSLu Baolu 659aeb9dd1dSLu Baolu ret = xdbc_early_setup(); 660aeb9dd1dSLu Baolu if (ret) { 661aeb9dd1dSLu Baolu pr_notice("failed to setup the connection to host\n"); 662aeb9dd1dSLu Baolu 663aeb9dd1dSLu Baolu xdbc_free_ring(&xdbc.evt_ring); 664aeb9dd1dSLu Baolu xdbc_free_ring(&xdbc.out_ring); 665aeb9dd1dSLu Baolu xdbc_free_ring(&xdbc.in_ring); 666aeb9dd1dSLu Baolu 667aeb9dd1dSLu Baolu if (xdbc.table_dma) 668*3ecc6834SMike Rapoport memblock_phys_free(xdbc.table_dma, PAGE_SIZE); 669aeb9dd1dSLu Baolu 670aeb9dd1dSLu Baolu if (xdbc.out_dma) 671*3ecc6834SMike Rapoport memblock_phys_free(xdbc.out_dma, PAGE_SIZE); 672aeb9dd1dSLu Baolu 673aeb9dd1dSLu Baolu xdbc.table_base = NULL; 674aeb9dd1dSLu Baolu xdbc.out_buf = NULL; 675aeb9dd1dSLu Baolu } 676aeb9dd1dSLu Baolu 677aeb9dd1dSLu Baolu return ret; 678aeb9dd1dSLu Baolu } 679aeb9dd1dSLu Baolu 680aeb9dd1dSLu Baolu static void xdbc_handle_port_status(struct xdbc_trb *evt_trb) 681aeb9dd1dSLu Baolu { 682aeb9dd1dSLu Baolu u32 port_reg; 683aeb9dd1dSLu Baolu 684aeb9dd1dSLu Baolu port_reg = readl(&xdbc.xdbc_reg->portsc); 685aeb9dd1dSLu Baolu if (port_reg & PORTSC_CONN_CHANGE) { 686aeb9dd1dSLu Baolu xdbc_trace("connect status change event\n"); 687aeb9dd1dSLu Baolu 688aeb9dd1dSLu Baolu /* Check whether cable unplugged: */ 689aeb9dd1dSLu Baolu if (!(port_reg & PORTSC_CONN_STATUS)) { 690aeb9dd1dSLu Baolu xdbc.flags = 0; 691aeb9dd1dSLu Baolu xdbc_trace("cable unplugged\n"); 692aeb9dd1dSLu Baolu } 693aeb9dd1dSLu Baolu } 694aeb9dd1dSLu Baolu 695aeb9dd1dSLu Baolu if (port_reg & PORTSC_RESET_CHANGE) 696aeb9dd1dSLu Baolu xdbc_trace("port reset change event\n"); 697aeb9dd1dSLu Baolu 698aeb9dd1dSLu Baolu if (port_reg & PORTSC_LINK_CHANGE) 699aeb9dd1dSLu Baolu xdbc_trace("port link status change event\n"); 700aeb9dd1dSLu Baolu 701aeb9dd1dSLu Baolu if (port_reg & PORTSC_CONFIG_CHANGE) 702aeb9dd1dSLu Baolu xdbc_trace("config error change\n"); 703aeb9dd1dSLu Baolu 704aeb9dd1dSLu Baolu /* Write back the value to clear RW1C bits: */ 705aeb9dd1dSLu Baolu writel(port_reg, &xdbc.xdbc_reg->portsc); 706aeb9dd1dSLu Baolu } 707aeb9dd1dSLu Baolu 708aeb9dd1dSLu Baolu static void xdbc_handle_tx_event(struct xdbc_trb *evt_trb) 709aeb9dd1dSLu Baolu { 710aeb9dd1dSLu Baolu u32 comp_code; 711aeb9dd1dSLu Baolu int ep_id; 712aeb9dd1dSLu Baolu 713aeb9dd1dSLu Baolu comp_code = GET_COMP_CODE(le32_to_cpu(evt_trb->field[2])); 714aeb9dd1dSLu Baolu ep_id = TRB_TO_EP_ID(le32_to_cpu(evt_trb->field[3])); 715aeb9dd1dSLu Baolu 716aeb9dd1dSLu Baolu switch (comp_code) { 717aeb9dd1dSLu Baolu case COMP_SUCCESS: 718aeb9dd1dSLu Baolu case COMP_SHORT_PACKET: 719aeb9dd1dSLu Baolu break; 720aeb9dd1dSLu Baolu case COMP_TRB_ERROR: 721aeb9dd1dSLu Baolu case COMP_BABBLE_DETECTED_ERROR: 722aeb9dd1dSLu Baolu case COMP_USB_TRANSACTION_ERROR: 723aeb9dd1dSLu Baolu case COMP_STALL_ERROR: 724aeb9dd1dSLu Baolu default: 7257dbdb53dSJann Horn if (ep_id == XDBC_EPID_OUT || ep_id == XDBC_EPID_OUT_INTEL) 726aeb9dd1dSLu Baolu xdbc.flags |= XDBC_FLAGS_OUT_STALL; 7277dbdb53dSJann Horn if (ep_id == XDBC_EPID_IN || ep_id == XDBC_EPID_IN_INTEL) 728aeb9dd1dSLu Baolu xdbc.flags |= XDBC_FLAGS_IN_STALL; 729aeb9dd1dSLu Baolu 730aeb9dd1dSLu Baolu xdbc_trace("endpoint %d stalled\n", ep_id); 731aeb9dd1dSLu Baolu break; 732aeb9dd1dSLu Baolu } 733aeb9dd1dSLu Baolu 7347dbdb53dSJann Horn if (ep_id == XDBC_EPID_IN || ep_id == XDBC_EPID_IN_INTEL) { 735aeb9dd1dSLu Baolu xdbc.flags &= ~XDBC_FLAGS_IN_PROCESS; 736aeb9dd1dSLu Baolu xdbc_bulk_transfer(NULL, XDBC_MAX_PACKET, true); 7377dbdb53dSJann Horn } else if (ep_id == XDBC_EPID_OUT || ep_id == XDBC_EPID_OUT_INTEL) { 738aeb9dd1dSLu Baolu xdbc.flags &= ~XDBC_FLAGS_OUT_PROCESS; 739aeb9dd1dSLu Baolu } else { 740aeb9dd1dSLu Baolu xdbc_trace("invalid endpoint id %d\n", ep_id); 741aeb9dd1dSLu Baolu } 742aeb9dd1dSLu Baolu } 743aeb9dd1dSLu Baolu 744aeb9dd1dSLu Baolu static void xdbc_handle_events(void) 745aeb9dd1dSLu Baolu { 746aeb9dd1dSLu Baolu struct xdbc_trb *evt_trb; 747aeb9dd1dSLu Baolu bool update_erdp = false; 748aeb9dd1dSLu Baolu u32 reg; 749aeb9dd1dSLu Baolu u8 cmd; 750aeb9dd1dSLu Baolu 751aeb9dd1dSLu Baolu cmd = read_pci_config_byte(xdbc.bus, xdbc.dev, xdbc.func, PCI_COMMAND); 752aeb9dd1dSLu Baolu if (!(cmd & PCI_COMMAND_MASTER)) { 753aeb9dd1dSLu Baolu cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; 754aeb9dd1dSLu Baolu write_pci_config_byte(xdbc.bus, xdbc.dev, xdbc.func, PCI_COMMAND, cmd); 755aeb9dd1dSLu Baolu } 756aeb9dd1dSLu Baolu 757aeb9dd1dSLu Baolu if (!(xdbc.flags & XDBC_FLAGS_INITIALIZED)) 758aeb9dd1dSLu Baolu return; 759aeb9dd1dSLu Baolu 760aeb9dd1dSLu Baolu /* Handle external reset events: */ 761aeb9dd1dSLu Baolu reg = readl(&xdbc.xdbc_reg->control); 762aeb9dd1dSLu Baolu if (!(reg & CTRL_DBC_ENABLE)) { 763aeb9dd1dSLu Baolu if (xdbc_handle_external_reset()) { 764aeb9dd1dSLu Baolu xdbc_trace("failed to recover connection\n"); 765aeb9dd1dSLu Baolu return; 766aeb9dd1dSLu Baolu } 767aeb9dd1dSLu Baolu } 768aeb9dd1dSLu Baolu 769aeb9dd1dSLu Baolu /* Handle configure-exit event: */ 770aeb9dd1dSLu Baolu reg = readl(&xdbc.xdbc_reg->control); 771aeb9dd1dSLu Baolu if (reg & CTRL_DBC_RUN_CHANGE) { 772aeb9dd1dSLu Baolu writel(reg, &xdbc.xdbc_reg->control); 773aeb9dd1dSLu Baolu if (reg & CTRL_DBC_RUN) 774aeb9dd1dSLu Baolu xdbc.flags |= XDBC_FLAGS_CONFIGURED; 775aeb9dd1dSLu Baolu else 776aeb9dd1dSLu Baolu xdbc.flags &= ~XDBC_FLAGS_CONFIGURED; 777aeb9dd1dSLu Baolu } 778aeb9dd1dSLu Baolu 779aeb9dd1dSLu Baolu /* Handle endpoint stall event: */ 780aeb9dd1dSLu Baolu reg = readl(&xdbc.xdbc_reg->control); 781aeb9dd1dSLu Baolu if (reg & CTRL_HALT_IN_TR) { 782aeb9dd1dSLu Baolu xdbc.flags |= XDBC_FLAGS_IN_STALL; 783aeb9dd1dSLu Baolu } else { 784aeb9dd1dSLu Baolu xdbc.flags &= ~XDBC_FLAGS_IN_STALL; 785aeb9dd1dSLu Baolu if (!(xdbc.flags & XDBC_FLAGS_IN_PROCESS)) 786aeb9dd1dSLu Baolu xdbc_bulk_transfer(NULL, XDBC_MAX_PACKET, true); 787aeb9dd1dSLu Baolu } 788aeb9dd1dSLu Baolu 789aeb9dd1dSLu Baolu if (reg & CTRL_HALT_OUT_TR) 790aeb9dd1dSLu Baolu xdbc.flags |= XDBC_FLAGS_OUT_STALL; 791aeb9dd1dSLu Baolu else 792aeb9dd1dSLu Baolu xdbc.flags &= ~XDBC_FLAGS_OUT_STALL; 793aeb9dd1dSLu Baolu 794aeb9dd1dSLu Baolu /* Handle the events in the event ring: */ 795aeb9dd1dSLu Baolu evt_trb = xdbc.evt_ring.dequeue; 796aeb9dd1dSLu Baolu while ((le32_to_cpu(evt_trb->field[3]) & TRB_CYCLE) == xdbc.evt_ring.cycle_state) { 797aeb9dd1dSLu Baolu /* 798aeb9dd1dSLu Baolu * Add a barrier between reading the cycle flag and any 799aeb9dd1dSLu Baolu * reads of the event's flags/data below: 800aeb9dd1dSLu Baolu */ 801aeb9dd1dSLu Baolu rmb(); 802aeb9dd1dSLu Baolu 803aeb9dd1dSLu Baolu switch ((le32_to_cpu(evt_trb->field[3]) & TRB_TYPE_BITMASK)) { 804aeb9dd1dSLu Baolu case TRB_TYPE(TRB_PORT_STATUS): 805aeb9dd1dSLu Baolu xdbc_handle_port_status(evt_trb); 806aeb9dd1dSLu Baolu break; 807aeb9dd1dSLu Baolu case TRB_TYPE(TRB_TRANSFER): 808aeb9dd1dSLu Baolu xdbc_handle_tx_event(evt_trb); 809aeb9dd1dSLu Baolu break; 810aeb9dd1dSLu Baolu default: 811aeb9dd1dSLu Baolu break; 812aeb9dd1dSLu Baolu } 813aeb9dd1dSLu Baolu 814aeb9dd1dSLu Baolu ++(xdbc.evt_ring.dequeue); 815aeb9dd1dSLu Baolu if (xdbc.evt_ring.dequeue == &xdbc.evt_seg.trbs[TRBS_PER_SEGMENT]) { 816aeb9dd1dSLu Baolu xdbc.evt_ring.dequeue = xdbc.evt_seg.trbs; 817aeb9dd1dSLu Baolu xdbc.evt_ring.cycle_state ^= 1; 818aeb9dd1dSLu Baolu } 819aeb9dd1dSLu Baolu 820aeb9dd1dSLu Baolu evt_trb = xdbc.evt_ring.dequeue; 821aeb9dd1dSLu Baolu update_erdp = true; 822aeb9dd1dSLu Baolu } 823aeb9dd1dSLu Baolu 824aeb9dd1dSLu Baolu /* Update event ring dequeue pointer: */ 825aeb9dd1dSLu Baolu if (update_erdp) 826aeb9dd1dSLu Baolu xdbc_write64(__pa(xdbc.evt_ring.dequeue), &xdbc.xdbc_reg->erdp); 827aeb9dd1dSLu Baolu } 828aeb9dd1dSLu Baolu 829aeb9dd1dSLu Baolu static int xdbc_bulk_write(const char *bytes, int size) 830aeb9dd1dSLu Baolu { 831aeb9dd1dSLu Baolu int ret, timeout = 0; 832aeb9dd1dSLu Baolu unsigned long flags; 833aeb9dd1dSLu Baolu 834aeb9dd1dSLu Baolu retry: 835aeb9dd1dSLu Baolu if (in_nmi()) { 836aeb9dd1dSLu Baolu if (!raw_spin_trylock_irqsave(&xdbc.lock, flags)) 837aeb9dd1dSLu Baolu return -EAGAIN; 838aeb9dd1dSLu Baolu } else { 839aeb9dd1dSLu Baolu raw_spin_lock_irqsave(&xdbc.lock, flags); 840aeb9dd1dSLu Baolu } 841aeb9dd1dSLu Baolu 842aeb9dd1dSLu Baolu xdbc_handle_events(); 843aeb9dd1dSLu Baolu 844aeb9dd1dSLu Baolu /* Check completion of the previous request: */ 845aeb9dd1dSLu Baolu if ((xdbc.flags & XDBC_FLAGS_OUT_PROCESS) && (timeout < 2000000)) { 846aeb9dd1dSLu Baolu raw_spin_unlock_irqrestore(&xdbc.lock, flags); 847aeb9dd1dSLu Baolu udelay(100); 848aeb9dd1dSLu Baolu timeout += 100; 849aeb9dd1dSLu Baolu goto retry; 850aeb9dd1dSLu Baolu } 851aeb9dd1dSLu Baolu 852aeb9dd1dSLu Baolu if (xdbc.flags & XDBC_FLAGS_OUT_PROCESS) { 853aeb9dd1dSLu Baolu raw_spin_unlock_irqrestore(&xdbc.lock, flags); 854aeb9dd1dSLu Baolu xdbc_trace("previous transfer not completed yet\n"); 855aeb9dd1dSLu Baolu 856aeb9dd1dSLu Baolu return -ETIMEDOUT; 857aeb9dd1dSLu Baolu } 858aeb9dd1dSLu Baolu 859aeb9dd1dSLu Baolu ret = xdbc_bulk_transfer((void *)bytes, size, false); 860aeb9dd1dSLu Baolu raw_spin_unlock_irqrestore(&xdbc.lock, flags); 861aeb9dd1dSLu Baolu 862aeb9dd1dSLu Baolu return ret; 863aeb9dd1dSLu Baolu } 864aeb9dd1dSLu Baolu 865aeb9dd1dSLu Baolu static void early_xdbc_write(struct console *con, const char *str, u32 n) 866aeb9dd1dSLu Baolu { 867aeb9dd1dSLu Baolu static char buf[XDBC_MAX_PACKET]; 868aeb9dd1dSLu Baolu int chunk, ret; 869aeb9dd1dSLu Baolu int use_cr = 0; 870aeb9dd1dSLu Baolu 871aeb9dd1dSLu Baolu if (!xdbc.xdbc_reg) 872aeb9dd1dSLu Baolu return; 873aeb9dd1dSLu Baolu memset(buf, 0, XDBC_MAX_PACKET); 874aeb9dd1dSLu Baolu while (n > 0) { 875aeb9dd1dSLu Baolu for (chunk = 0; chunk < XDBC_MAX_PACKET && n > 0; str++, chunk++, n--) { 876aeb9dd1dSLu Baolu 877aeb9dd1dSLu Baolu if (!use_cr && *str == '\n') { 878aeb9dd1dSLu Baolu use_cr = 1; 879aeb9dd1dSLu Baolu buf[chunk] = '\r'; 880aeb9dd1dSLu Baolu str--; 881aeb9dd1dSLu Baolu n++; 882aeb9dd1dSLu Baolu continue; 883aeb9dd1dSLu Baolu } 884aeb9dd1dSLu Baolu 885aeb9dd1dSLu Baolu if (use_cr) 886aeb9dd1dSLu Baolu use_cr = 0; 887aeb9dd1dSLu Baolu buf[chunk] = *str; 888aeb9dd1dSLu Baolu } 889aeb9dd1dSLu Baolu 890aeb9dd1dSLu Baolu if (chunk > 0) { 891aeb9dd1dSLu Baolu ret = xdbc_bulk_write(buf, chunk); 892aeb9dd1dSLu Baolu if (ret < 0) 893aeb9dd1dSLu Baolu xdbc_trace("missed message {%s}\n", buf); 894aeb9dd1dSLu Baolu } 895aeb9dd1dSLu Baolu } 896aeb9dd1dSLu Baolu } 897aeb9dd1dSLu Baolu 898aeb9dd1dSLu Baolu static struct console early_xdbc_console = { 899aeb9dd1dSLu Baolu .name = "earlyxdbc", 900aeb9dd1dSLu Baolu .write = early_xdbc_write, 901aeb9dd1dSLu Baolu .flags = CON_PRINTBUFFER, 902aeb9dd1dSLu Baolu .index = -1, 903aeb9dd1dSLu Baolu }; 904aeb9dd1dSLu Baolu 905aeb9dd1dSLu Baolu void __init early_xdbc_register_console(void) 906aeb9dd1dSLu Baolu { 907aeb9dd1dSLu Baolu if (early_console) 908aeb9dd1dSLu Baolu return; 909aeb9dd1dSLu Baolu 910aeb9dd1dSLu Baolu early_console = &early_xdbc_console; 911aeb9dd1dSLu Baolu if (early_console_keep) 912aeb9dd1dSLu Baolu early_console->flags &= ~CON_BOOT; 913aeb9dd1dSLu Baolu else 914aeb9dd1dSLu Baolu early_console->flags |= CON_BOOT; 915aeb9dd1dSLu Baolu register_console(early_console); 916aeb9dd1dSLu Baolu } 917aeb9dd1dSLu Baolu 918aeb9dd1dSLu Baolu static void xdbc_unregister_console(void) 919aeb9dd1dSLu Baolu { 920aeb9dd1dSLu Baolu if (early_xdbc_console.flags & CON_ENABLED) 921aeb9dd1dSLu Baolu unregister_console(&early_xdbc_console); 922aeb9dd1dSLu Baolu } 923aeb9dd1dSLu Baolu 924aeb9dd1dSLu Baolu static int xdbc_scrub_function(void *ptr) 925aeb9dd1dSLu Baolu { 926aeb9dd1dSLu Baolu unsigned long flags; 927aeb9dd1dSLu Baolu 928aeb9dd1dSLu Baolu while (true) { 929aeb9dd1dSLu Baolu raw_spin_lock_irqsave(&xdbc.lock, flags); 930aeb9dd1dSLu Baolu xdbc_handle_events(); 931aeb9dd1dSLu Baolu 932aeb9dd1dSLu Baolu if (!(xdbc.flags & XDBC_FLAGS_INITIALIZED)) { 933aeb9dd1dSLu Baolu raw_spin_unlock_irqrestore(&xdbc.lock, flags); 934aeb9dd1dSLu Baolu break; 935aeb9dd1dSLu Baolu } 936aeb9dd1dSLu Baolu 937aeb9dd1dSLu Baolu raw_spin_unlock_irqrestore(&xdbc.lock, flags); 938aeb9dd1dSLu Baolu schedule_timeout_interruptible(1); 939aeb9dd1dSLu Baolu } 940aeb9dd1dSLu Baolu 941aeb9dd1dSLu Baolu xdbc_unregister_console(); 942aeb9dd1dSLu Baolu writel(0, &xdbc.xdbc_reg->control); 943aeb9dd1dSLu Baolu xdbc_trace("dbc scrub function exits\n"); 944aeb9dd1dSLu Baolu 945aeb9dd1dSLu Baolu return 0; 946aeb9dd1dSLu Baolu } 947aeb9dd1dSLu Baolu 948aeb9dd1dSLu Baolu static int __init xdbc_init(void) 949aeb9dd1dSLu Baolu { 950aeb9dd1dSLu Baolu unsigned long flags; 951aeb9dd1dSLu Baolu void __iomem *base; 952aeb9dd1dSLu Baolu int ret = 0; 953aeb9dd1dSLu Baolu u32 offset; 954aeb9dd1dSLu Baolu 955aeb9dd1dSLu Baolu if (!(xdbc.flags & XDBC_FLAGS_INITIALIZED)) 956aeb9dd1dSLu Baolu return 0; 957aeb9dd1dSLu Baolu 958aeb9dd1dSLu Baolu /* 959aeb9dd1dSLu Baolu * It's time to shut down the DbC, so that the debug 960aeb9dd1dSLu Baolu * port can be reused by the host controller: 961aeb9dd1dSLu Baolu */ 962aeb9dd1dSLu Baolu if (early_xdbc_console.index == -1 || 963aeb9dd1dSLu Baolu (early_xdbc_console.flags & CON_BOOT)) { 964aeb9dd1dSLu Baolu xdbc_trace("hardware not used anymore\n"); 965aeb9dd1dSLu Baolu goto free_and_quit; 966aeb9dd1dSLu Baolu } 967aeb9dd1dSLu Baolu 9684bdc0d67SChristoph Hellwig base = ioremap(xdbc.xhci_start, xdbc.xhci_length); 969aeb9dd1dSLu Baolu if (!base) { 970aeb9dd1dSLu Baolu xdbc_trace("failed to remap the io address\n"); 971aeb9dd1dSLu Baolu ret = -ENOMEM; 972aeb9dd1dSLu Baolu goto free_and_quit; 973aeb9dd1dSLu Baolu } 974aeb9dd1dSLu Baolu 975aeb9dd1dSLu Baolu raw_spin_lock_irqsave(&xdbc.lock, flags); 976aeb9dd1dSLu Baolu early_iounmap(xdbc.xhci_base, xdbc.xhci_length); 977aeb9dd1dSLu Baolu xdbc.xhci_base = base; 978aeb9dd1dSLu Baolu offset = xhci_find_next_ext_cap(xdbc.xhci_base, 0, XHCI_EXT_CAPS_DEBUG); 979aeb9dd1dSLu Baolu xdbc.xdbc_reg = (struct xdbc_regs __iomem *)(xdbc.xhci_base + offset); 980aeb9dd1dSLu Baolu raw_spin_unlock_irqrestore(&xdbc.lock, flags); 981aeb9dd1dSLu Baolu 982aeb9dd1dSLu Baolu kthread_run(xdbc_scrub_function, NULL, "%s", "xdbc"); 983aeb9dd1dSLu Baolu 984aeb9dd1dSLu Baolu return 0; 985aeb9dd1dSLu Baolu 986aeb9dd1dSLu Baolu free_and_quit: 987aeb9dd1dSLu Baolu xdbc_free_ring(&xdbc.evt_ring); 988aeb9dd1dSLu Baolu xdbc_free_ring(&xdbc.out_ring); 989aeb9dd1dSLu Baolu xdbc_free_ring(&xdbc.in_ring); 990*3ecc6834SMike Rapoport memblock_phys_free(xdbc.table_dma, PAGE_SIZE); 991*3ecc6834SMike Rapoport memblock_phys_free(xdbc.out_dma, PAGE_SIZE); 992aeb9dd1dSLu Baolu writel(0, &xdbc.xdbc_reg->control); 993aeb9dd1dSLu Baolu early_iounmap(xdbc.xhci_base, xdbc.xhci_length); 994aeb9dd1dSLu Baolu 995aeb9dd1dSLu Baolu return ret; 996aeb9dd1dSLu Baolu } 997aeb9dd1dSLu Baolu subsys_initcall(xdbc_init); 998