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