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