1*67f4addbSFrank Haverkamp /** 2*67f4addbSFrank Haverkamp * IBM Accelerator Family 'GenWQE' 3*67f4addbSFrank Haverkamp * 4*67f4addbSFrank Haverkamp * (C) Copyright IBM Corp. 2013 5*67f4addbSFrank Haverkamp * 6*67f4addbSFrank Haverkamp * Author: Frank Haverkamp <haver@linux.vnet.ibm.com> 7*67f4addbSFrank Haverkamp * Author: Joerg-Stephan Vogt <jsvogt@de.ibm.com> 8*67f4addbSFrank Haverkamp * Author: Michael Jung <mijung@de.ibm.com> 9*67f4addbSFrank Haverkamp * Author: Michael Ruettger <michael@ibmra.de> 10*67f4addbSFrank Haverkamp * 11*67f4addbSFrank Haverkamp * This program is free software; you can redistribute it and/or modify 12*67f4addbSFrank Haverkamp * it under the terms of the GNU General Public License (version 2 only) 13*67f4addbSFrank Haverkamp * as published by the Free Software Foundation. 14*67f4addbSFrank Haverkamp * 15*67f4addbSFrank Haverkamp * This program is distributed in the hope that it will be useful, 16*67f4addbSFrank Haverkamp * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*67f4addbSFrank Haverkamp * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*67f4addbSFrank Haverkamp * GNU General Public License for more details. 19*67f4addbSFrank Haverkamp */ 20*67f4addbSFrank Haverkamp 21*67f4addbSFrank Haverkamp /* 22*67f4addbSFrank Haverkamp * Miscelanous functionality used in the other GenWQE driver parts. 23*67f4addbSFrank Haverkamp */ 24*67f4addbSFrank Haverkamp 25*67f4addbSFrank Haverkamp #include <linux/kernel.h> 26*67f4addbSFrank Haverkamp #include <linux/dma-mapping.h> 27*67f4addbSFrank Haverkamp #include <linux/sched.h> 28*67f4addbSFrank Haverkamp #include <linux/vmalloc.h> 29*67f4addbSFrank Haverkamp #include <linux/page-flags.h> 30*67f4addbSFrank Haverkamp #include <linux/scatterlist.h> 31*67f4addbSFrank Haverkamp #include <linux/hugetlb.h> 32*67f4addbSFrank Haverkamp #include <linux/iommu.h> 33*67f4addbSFrank Haverkamp #include <linux/delay.h> 34*67f4addbSFrank Haverkamp #include <linux/pci.h> 35*67f4addbSFrank Haverkamp #include <linux/dma-mapping.h> 36*67f4addbSFrank Haverkamp #include <linux/ctype.h> 37*67f4addbSFrank Haverkamp #include <linux/module.h> 38*67f4addbSFrank Haverkamp #include <linux/platform_device.h> 39*67f4addbSFrank Haverkamp #include <linux/delay.h> 40*67f4addbSFrank Haverkamp #include <asm/pgtable.h> 41*67f4addbSFrank Haverkamp 42*67f4addbSFrank Haverkamp #include "genwqe_driver.h" 43*67f4addbSFrank Haverkamp #include "card_base.h" 44*67f4addbSFrank Haverkamp #include "card_ddcb.h" 45*67f4addbSFrank Haverkamp 46*67f4addbSFrank Haverkamp /** 47*67f4addbSFrank Haverkamp * __genwqe_writeq() - Write 64-bit register 48*67f4addbSFrank Haverkamp * @cd: genwqe device descriptor 49*67f4addbSFrank Haverkamp * @byte_offs: byte offset within BAR 50*67f4addbSFrank Haverkamp * @val: 64-bit value 51*67f4addbSFrank Haverkamp * 52*67f4addbSFrank Haverkamp * Return: 0 if success; < 0 if error 53*67f4addbSFrank Haverkamp */ 54*67f4addbSFrank Haverkamp int __genwqe_writeq(struct genwqe_dev *cd, u64 byte_offs, u64 val) 55*67f4addbSFrank Haverkamp { 56*67f4addbSFrank Haverkamp if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE) 57*67f4addbSFrank Haverkamp return -EIO; 58*67f4addbSFrank Haverkamp 59*67f4addbSFrank Haverkamp if (cd->mmio == NULL) 60*67f4addbSFrank Haverkamp return -EIO; 61*67f4addbSFrank Haverkamp 62*67f4addbSFrank Haverkamp __raw_writeq(cpu_to_be64((val)), (cd->mmio + byte_offs)); 63*67f4addbSFrank Haverkamp return 0; 64*67f4addbSFrank Haverkamp } 65*67f4addbSFrank Haverkamp 66*67f4addbSFrank Haverkamp /** 67*67f4addbSFrank Haverkamp * __genwqe_readq() - Read 64-bit register 68*67f4addbSFrank Haverkamp * @cd: genwqe device descriptor 69*67f4addbSFrank Haverkamp * @byte_offs: offset within BAR 70*67f4addbSFrank Haverkamp * 71*67f4addbSFrank Haverkamp * Return: value from register 72*67f4addbSFrank Haverkamp */ 73*67f4addbSFrank Haverkamp u64 __genwqe_readq(struct genwqe_dev *cd, u64 byte_offs) 74*67f4addbSFrank Haverkamp { 75*67f4addbSFrank Haverkamp u64 val; 76*67f4addbSFrank Haverkamp 77*67f4addbSFrank Haverkamp if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE) 78*67f4addbSFrank Haverkamp return 0xffffffffffffffffull; 79*67f4addbSFrank Haverkamp 80*67f4addbSFrank Haverkamp if ((cd->err_inject & GENWQE_INJECT_GFIR_FATAL) && 81*67f4addbSFrank Haverkamp (byte_offs == IO_SLC_CFGREG_GFIR)) 82*67f4addbSFrank Haverkamp return 0x000000000000ffffull; 83*67f4addbSFrank Haverkamp 84*67f4addbSFrank Haverkamp if ((cd->err_inject & GENWQE_INJECT_GFIR_INFO) && 85*67f4addbSFrank Haverkamp (byte_offs == IO_SLC_CFGREG_GFIR)) 86*67f4addbSFrank Haverkamp return 0x00000000ffff0000ull; 87*67f4addbSFrank Haverkamp 88*67f4addbSFrank Haverkamp if (cd->mmio == NULL) 89*67f4addbSFrank Haverkamp return 0xffffffffffffffffull; 90*67f4addbSFrank Haverkamp 91*67f4addbSFrank Haverkamp val = be64_to_cpu(__raw_readq(cd->mmio + byte_offs)); 92*67f4addbSFrank Haverkamp return val; 93*67f4addbSFrank Haverkamp } 94*67f4addbSFrank Haverkamp 95*67f4addbSFrank Haverkamp /** 96*67f4addbSFrank Haverkamp * __genwqe_writel() - Write 32-bit register 97*67f4addbSFrank Haverkamp * @cd: genwqe device descriptor 98*67f4addbSFrank Haverkamp * @byte_offs: byte offset within BAR 99*67f4addbSFrank Haverkamp * @val: 32-bit value 100*67f4addbSFrank Haverkamp * 101*67f4addbSFrank Haverkamp * Return: 0 if success; < 0 if error 102*67f4addbSFrank Haverkamp */ 103*67f4addbSFrank Haverkamp int __genwqe_writel(struct genwqe_dev *cd, u64 byte_offs, u32 val) 104*67f4addbSFrank Haverkamp { 105*67f4addbSFrank Haverkamp if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE) 106*67f4addbSFrank Haverkamp return -EIO; 107*67f4addbSFrank Haverkamp 108*67f4addbSFrank Haverkamp if (cd->mmio == NULL) 109*67f4addbSFrank Haverkamp return -EIO; 110*67f4addbSFrank Haverkamp 111*67f4addbSFrank Haverkamp __raw_writel(cpu_to_be32((val)), cd->mmio + byte_offs); 112*67f4addbSFrank Haverkamp return 0; 113*67f4addbSFrank Haverkamp } 114*67f4addbSFrank Haverkamp 115*67f4addbSFrank Haverkamp /** 116*67f4addbSFrank Haverkamp * __genwqe_readl() - Read 32-bit register 117*67f4addbSFrank Haverkamp * @cd: genwqe device descriptor 118*67f4addbSFrank Haverkamp * @byte_offs: offset within BAR 119*67f4addbSFrank Haverkamp * 120*67f4addbSFrank Haverkamp * Return: Value from register 121*67f4addbSFrank Haverkamp */ 122*67f4addbSFrank Haverkamp u32 __genwqe_readl(struct genwqe_dev *cd, u64 byte_offs) 123*67f4addbSFrank Haverkamp { 124*67f4addbSFrank Haverkamp if (cd->err_inject & GENWQE_INJECT_HARDWARE_FAILURE) 125*67f4addbSFrank Haverkamp return 0xffffffff; 126*67f4addbSFrank Haverkamp 127*67f4addbSFrank Haverkamp if (cd->mmio == NULL) 128*67f4addbSFrank Haverkamp return 0xffffffff; 129*67f4addbSFrank Haverkamp 130*67f4addbSFrank Haverkamp return be32_to_cpu(__raw_readl(cd->mmio + byte_offs)); 131*67f4addbSFrank Haverkamp } 132*67f4addbSFrank Haverkamp 133*67f4addbSFrank Haverkamp /** 134*67f4addbSFrank Haverkamp * genwqe_read_app_id() - Extract app_id 135*67f4addbSFrank Haverkamp * 136*67f4addbSFrank Haverkamp * app_unitcfg need to be filled with valid data first 137*67f4addbSFrank Haverkamp */ 138*67f4addbSFrank Haverkamp int genwqe_read_app_id(struct genwqe_dev *cd, char *app_name, int len) 139*67f4addbSFrank Haverkamp { 140*67f4addbSFrank Haverkamp int i, j; 141*67f4addbSFrank Haverkamp u32 app_id = (u32)cd->app_unitcfg; 142*67f4addbSFrank Haverkamp 143*67f4addbSFrank Haverkamp memset(app_name, 0, len); 144*67f4addbSFrank Haverkamp for (i = 0, j = 0; j < min(len, 4); j++) { 145*67f4addbSFrank Haverkamp char ch = (char)((app_id >> (24 - j*8)) & 0xff); 146*67f4addbSFrank Haverkamp if (ch == ' ') 147*67f4addbSFrank Haverkamp continue; 148*67f4addbSFrank Haverkamp app_name[i++] = isprint(ch) ? ch : 'X'; 149*67f4addbSFrank Haverkamp } 150*67f4addbSFrank Haverkamp return i; 151*67f4addbSFrank Haverkamp } 152*67f4addbSFrank Haverkamp 153*67f4addbSFrank Haverkamp /** 154*67f4addbSFrank Haverkamp * genwqe_init_crc32() - Prepare a lookup table for fast crc32 calculations 155*67f4addbSFrank Haverkamp * 156*67f4addbSFrank Haverkamp * Existing kernel functions seem to use a different polynom, 157*67f4addbSFrank Haverkamp * therefore we could not use them here. 158*67f4addbSFrank Haverkamp * 159*67f4addbSFrank Haverkamp * Genwqe's Polynomial = 0x20044009 160*67f4addbSFrank Haverkamp */ 161*67f4addbSFrank Haverkamp #define CRC32_POLYNOMIAL 0x20044009 162*67f4addbSFrank Haverkamp static u32 crc32_tab[256]; /* crc32 lookup table */ 163*67f4addbSFrank Haverkamp 164*67f4addbSFrank Haverkamp void genwqe_init_crc32(void) 165*67f4addbSFrank Haverkamp { 166*67f4addbSFrank Haverkamp int i, j; 167*67f4addbSFrank Haverkamp u32 crc; 168*67f4addbSFrank Haverkamp 169*67f4addbSFrank Haverkamp for (i = 0; i < 256; i++) { 170*67f4addbSFrank Haverkamp crc = i << 24; 171*67f4addbSFrank Haverkamp for (j = 0; j < 8; j++) { 172*67f4addbSFrank Haverkamp if (crc & 0x80000000) 173*67f4addbSFrank Haverkamp crc = (crc << 1) ^ CRC32_POLYNOMIAL; 174*67f4addbSFrank Haverkamp else 175*67f4addbSFrank Haverkamp crc = (crc << 1); 176*67f4addbSFrank Haverkamp } 177*67f4addbSFrank Haverkamp crc32_tab[i] = crc; 178*67f4addbSFrank Haverkamp } 179*67f4addbSFrank Haverkamp } 180*67f4addbSFrank Haverkamp 181*67f4addbSFrank Haverkamp /** 182*67f4addbSFrank Haverkamp * genwqe_crc32() - Generate 32-bit crc as required for DDCBs 183*67f4addbSFrank Haverkamp * @buff: pointer to data buffer 184*67f4addbSFrank Haverkamp * @len: length of data for calculation 185*67f4addbSFrank Haverkamp * @init: initial crc (0xffffffff at start) 186*67f4addbSFrank Haverkamp * 187*67f4addbSFrank Haverkamp * polynomial = x^32 * + x^29 + x^18 + x^14 + x^3 + 1 (0x20044009) 188*67f4addbSFrank Haverkamp 189*67f4addbSFrank Haverkamp * Example: 4 bytes 0x01 0x02 0x03 0x04 with init=0xffffffff should 190*67f4addbSFrank Haverkamp * result in a crc32 of 0xf33cb7d3. 191*67f4addbSFrank Haverkamp * 192*67f4addbSFrank Haverkamp * The existing kernel crc functions did not cover this polynom yet. 193*67f4addbSFrank Haverkamp * 194*67f4addbSFrank Haverkamp * Return: crc32 checksum. 195*67f4addbSFrank Haverkamp */ 196*67f4addbSFrank Haverkamp u32 genwqe_crc32(u8 *buff, size_t len, u32 init) 197*67f4addbSFrank Haverkamp { 198*67f4addbSFrank Haverkamp int i; 199*67f4addbSFrank Haverkamp u32 crc; 200*67f4addbSFrank Haverkamp 201*67f4addbSFrank Haverkamp crc = init; 202*67f4addbSFrank Haverkamp while (len--) { 203*67f4addbSFrank Haverkamp i = ((crc >> 24) ^ *buff++) & 0xFF; 204*67f4addbSFrank Haverkamp crc = (crc << 8) ^ crc32_tab[i]; 205*67f4addbSFrank Haverkamp } 206*67f4addbSFrank Haverkamp return crc; 207*67f4addbSFrank Haverkamp } 208*67f4addbSFrank Haverkamp 209*67f4addbSFrank Haverkamp void *__genwqe_alloc_consistent(struct genwqe_dev *cd, size_t size, 210*67f4addbSFrank Haverkamp dma_addr_t *dma_handle) 211*67f4addbSFrank Haverkamp { 212*67f4addbSFrank Haverkamp if (get_order(size) > MAX_ORDER) 213*67f4addbSFrank Haverkamp return NULL; 214*67f4addbSFrank Haverkamp 215*67f4addbSFrank Haverkamp return pci_alloc_consistent(cd->pci_dev, size, dma_handle); 216*67f4addbSFrank Haverkamp } 217*67f4addbSFrank Haverkamp 218*67f4addbSFrank Haverkamp void __genwqe_free_consistent(struct genwqe_dev *cd, size_t size, 219*67f4addbSFrank Haverkamp void *vaddr, dma_addr_t dma_handle) 220*67f4addbSFrank Haverkamp { 221*67f4addbSFrank Haverkamp if (vaddr == NULL) 222*67f4addbSFrank Haverkamp return; 223*67f4addbSFrank Haverkamp 224*67f4addbSFrank Haverkamp pci_free_consistent(cd->pci_dev, size, vaddr, dma_handle); 225*67f4addbSFrank Haverkamp } 226*67f4addbSFrank Haverkamp 227*67f4addbSFrank Haverkamp static void genwqe_unmap_pages(struct genwqe_dev *cd, dma_addr_t *dma_list, 228*67f4addbSFrank Haverkamp int num_pages) 229*67f4addbSFrank Haverkamp { 230*67f4addbSFrank Haverkamp int i; 231*67f4addbSFrank Haverkamp struct pci_dev *pci_dev = cd->pci_dev; 232*67f4addbSFrank Haverkamp 233*67f4addbSFrank Haverkamp for (i = 0; (i < num_pages) && (dma_list[i] != 0x0); i++) { 234*67f4addbSFrank Haverkamp pci_unmap_page(pci_dev, dma_list[i], 235*67f4addbSFrank Haverkamp PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 236*67f4addbSFrank Haverkamp dma_list[i] = 0x0; 237*67f4addbSFrank Haverkamp } 238*67f4addbSFrank Haverkamp } 239*67f4addbSFrank Haverkamp 240*67f4addbSFrank Haverkamp static int genwqe_map_pages(struct genwqe_dev *cd, 241*67f4addbSFrank Haverkamp struct page **page_list, int num_pages, 242*67f4addbSFrank Haverkamp dma_addr_t *dma_list) 243*67f4addbSFrank Haverkamp { 244*67f4addbSFrank Haverkamp int i; 245*67f4addbSFrank Haverkamp struct pci_dev *pci_dev = cd->pci_dev; 246*67f4addbSFrank Haverkamp 247*67f4addbSFrank Haverkamp /* establish DMA mapping for requested pages */ 248*67f4addbSFrank Haverkamp for (i = 0; i < num_pages; i++) { 249*67f4addbSFrank Haverkamp dma_addr_t daddr; 250*67f4addbSFrank Haverkamp 251*67f4addbSFrank Haverkamp dma_list[i] = 0x0; 252*67f4addbSFrank Haverkamp daddr = pci_map_page(pci_dev, page_list[i], 253*67f4addbSFrank Haverkamp 0, /* map_offs */ 254*67f4addbSFrank Haverkamp PAGE_SIZE, 255*67f4addbSFrank Haverkamp PCI_DMA_BIDIRECTIONAL); /* FIXME rd/rw */ 256*67f4addbSFrank Haverkamp 257*67f4addbSFrank Haverkamp if (pci_dma_mapping_error(pci_dev, daddr)) { 258*67f4addbSFrank Haverkamp dev_err(&pci_dev->dev, 259*67f4addbSFrank Haverkamp "[%s] err: no dma addr daddr=%016llx!\n", 260*67f4addbSFrank Haverkamp __func__, (long long)daddr); 261*67f4addbSFrank Haverkamp goto err; 262*67f4addbSFrank Haverkamp } 263*67f4addbSFrank Haverkamp 264*67f4addbSFrank Haverkamp dma_list[i] = daddr; 265*67f4addbSFrank Haverkamp } 266*67f4addbSFrank Haverkamp return 0; 267*67f4addbSFrank Haverkamp 268*67f4addbSFrank Haverkamp err: 269*67f4addbSFrank Haverkamp genwqe_unmap_pages(cd, dma_list, num_pages); 270*67f4addbSFrank Haverkamp return -EIO; 271*67f4addbSFrank Haverkamp } 272*67f4addbSFrank Haverkamp 273*67f4addbSFrank Haverkamp static int genwqe_sgl_size(int num_pages) 274*67f4addbSFrank Haverkamp { 275*67f4addbSFrank Haverkamp int len, num_tlb = num_pages / 7; 276*67f4addbSFrank Haverkamp 277*67f4addbSFrank Haverkamp len = sizeof(struct sg_entry) * (num_pages+num_tlb + 1); 278*67f4addbSFrank Haverkamp return roundup(len, PAGE_SIZE); 279*67f4addbSFrank Haverkamp } 280*67f4addbSFrank Haverkamp 281*67f4addbSFrank Haverkamp struct sg_entry *genwqe_alloc_sgl(struct genwqe_dev *cd, int num_pages, 282*67f4addbSFrank Haverkamp dma_addr_t *dma_addr, size_t *sgl_size) 283*67f4addbSFrank Haverkamp { 284*67f4addbSFrank Haverkamp struct pci_dev *pci_dev = cd->pci_dev; 285*67f4addbSFrank Haverkamp struct sg_entry *sgl; 286*67f4addbSFrank Haverkamp 287*67f4addbSFrank Haverkamp *sgl_size = genwqe_sgl_size(num_pages); 288*67f4addbSFrank Haverkamp if (get_order(*sgl_size) > MAX_ORDER) { 289*67f4addbSFrank Haverkamp dev_err(&pci_dev->dev, 290*67f4addbSFrank Haverkamp "[%s] err: too much memory requested!\n", __func__); 291*67f4addbSFrank Haverkamp return NULL; 292*67f4addbSFrank Haverkamp } 293*67f4addbSFrank Haverkamp 294*67f4addbSFrank Haverkamp sgl = __genwqe_alloc_consistent(cd, *sgl_size, dma_addr); 295*67f4addbSFrank Haverkamp if (sgl == NULL) { 296*67f4addbSFrank Haverkamp dev_err(&pci_dev->dev, 297*67f4addbSFrank Haverkamp "[%s] err: no memory available!\n", __func__); 298*67f4addbSFrank Haverkamp return NULL; 299*67f4addbSFrank Haverkamp } 300*67f4addbSFrank Haverkamp 301*67f4addbSFrank Haverkamp return sgl; 302*67f4addbSFrank Haverkamp } 303*67f4addbSFrank Haverkamp 304*67f4addbSFrank Haverkamp int genwqe_setup_sgl(struct genwqe_dev *cd, 305*67f4addbSFrank Haverkamp unsigned long offs, 306*67f4addbSFrank Haverkamp unsigned long size, 307*67f4addbSFrank Haverkamp struct sg_entry *sgl, 308*67f4addbSFrank Haverkamp dma_addr_t dma_addr, size_t sgl_size, 309*67f4addbSFrank Haverkamp dma_addr_t *dma_list, int page_offs, int num_pages) 310*67f4addbSFrank Haverkamp { 311*67f4addbSFrank Haverkamp int i = 0, j = 0, p; 312*67f4addbSFrank Haverkamp unsigned long dma_offs, map_offs; 313*67f4addbSFrank Haverkamp struct pci_dev *pci_dev = cd->pci_dev; 314*67f4addbSFrank Haverkamp dma_addr_t prev_daddr = 0; 315*67f4addbSFrank Haverkamp struct sg_entry *s, *last_s = NULL; 316*67f4addbSFrank Haverkamp 317*67f4addbSFrank Haverkamp /* sanity checks */ 318*67f4addbSFrank Haverkamp if (offs > PAGE_SIZE) { 319*67f4addbSFrank Haverkamp dev_err(&pci_dev->dev, 320*67f4addbSFrank Haverkamp "[%s] too large start offs %08lx\n", __func__, offs); 321*67f4addbSFrank Haverkamp return -EFAULT; 322*67f4addbSFrank Haverkamp } 323*67f4addbSFrank Haverkamp if (sgl_size < genwqe_sgl_size(num_pages)) { 324*67f4addbSFrank Haverkamp dev_err(&pci_dev->dev, 325*67f4addbSFrank Haverkamp "[%s] sgl_size too small %08lx for %d pages\n", 326*67f4addbSFrank Haverkamp __func__, sgl_size, num_pages); 327*67f4addbSFrank Haverkamp return -EFAULT; 328*67f4addbSFrank Haverkamp } 329*67f4addbSFrank Haverkamp 330*67f4addbSFrank Haverkamp dma_offs = 128; /* next block if needed/dma_offset */ 331*67f4addbSFrank Haverkamp map_offs = offs; /* offset in first page */ 332*67f4addbSFrank Haverkamp 333*67f4addbSFrank Haverkamp s = &sgl[0]; /* first set of 8 entries */ 334*67f4addbSFrank Haverkamp p = 0; /* page */ 335*67f4addbSFrank Haverkamp while (p < num_pages) { 336*67f4addbSFrank Haverkamp dma_addr_t daddr; 337*67f4addbSFrank Haverkamp unsigned int size_to_map; 338*67f4addbSFrank Haverkamp 339*67f4addbSFrank Haverkamp /* always write the chaining entry, cleanup is done later */ 340*67f4addbSFrank Haverkamp j = 0; 341*67f4addbSFrank Haverkamp s[j].target_addr = cpu_to_be64(dma_addr + dma_offs); 342*67f4addbSFrank Haverkamp s[j].len = cpu_to_be32(128); 343*67f4addbSFrank Haverkamp s[j].flags = cpu_to_be32(SG_CHAINED); 344*67f4addbSFrank Haverkamp j++; 345*67f4addbSFrank Haverkamp 346*67f4addbSFrank Haverkamp while (j < 8) { 347*67f4addbSFrank Haverkamp /* DMA mapping for requested page, offs, size */ 348*67f4addbSFrank Haverkamp size_to_map = min(size, PAGE_SIZE - map_offs); 349*67f4addbSFrank Haverkamp daddr = dma_list[page_offs + p] + map_offs; 350*67f4addbSFrank Haverkamp size -= size_to_map; 351*67f4addbSFrank Haverkamp map_offs = 0; 352*67f4addbSFrank Haverkamp 353*67f4addbSFrank Haverkamp if (prev_daddr == daddr) { 354*67f4addbSFrank Haverkamp u32 prev_len = be32_to_cpu(last_s->len); 355*67f4addbSFrank Haverkamp 356*67f4addbSFrank Haverkamp /* pr_info("daddr combining: " 357*67f4addbSFrank Haverkamp "%016llx/%08x -> %016llx\n", 358*67f4addbSFrank Haverkamp prev_daddr, prev_len, daddr); */ 359*67f4addbSFrank Haverkamp 360*67f4addbSFrank Haverkamp last_s->len = cpu_to_be32(prev_len + 361*67f4addbSFrank Haverkamp size_to_map); 362*67f4addbSFrank Haverkamp 363*67f4addbSFrank Haverkamp p++; /* process next page */ 364*67f4addbSFrank Haverkamp if (p == num_pages) 365*67f4addbSFrank Haverkamp goto fixup; /* nothing to do */ 366*67f4addbSFrank Haverkamp 367*67f4addbSFrank Haverkamp prev_daddr = daddr + size_to_map; 368*67f4addbSFrank Haverkamp continue; 369*67f4addbSFrank Haverkamp } 370*67f4addbSFrank Haverkamp 371*67f4addbSFrank Haverkamp /* start new entry */ 372*67f4addbSFrank Haverkamp s[j].target_addr = cpu_to_be64(daddr); 373*67f4addbSFrank Haverkamp s[j].len = cpu_to_be32(size_to_map); 374*67f4addbSFrank Haverkamp s[j].flags = cpu_to_be32(SG_DATA); 375*67f4addbSFrank Haverkamp prev_daddr = daddr + size_to_map; 376*67f4addbSFrank Haverkamp last_s = &s[j]; 377*67f4addbSFrank Haverkamp j++; 378*67f4addbSFrank Haverkamp 379*67f4addbSFrank Haverkamp p++; /* process next page */ 380*67f4addbSFrank Haverkamp if (p == num_pages) 381*67f4addbSFrank Haverkamp goto fixup; /* nothing to do */ 382*67f4addbSFrank Haverkamp } 383*67f4addbSFrank Haverkamp dma_offs += 128; 384*67f4addbSFrank Haverkamp s += 8; /* continue 8 elements further */ 385*67f4addbSFrank Haverkamp } 386*67f4addbSFrank Haverkamp fixup: 387*67f4addbSFrank Haverkamp if (j == 1) { /* combining happend on last entry! */ 388*67f4addbSFrank Haverkamp s -= 8; /* full shift needed on previous sgl block */ 389*67f4addbSFrank Haverkamp j = 7; /* shift all elements */ 390*67f4addbSFrank Haverkamp } 391*67f4addbSFrank Haverkamp 392*67f4addbSFrank Haverkamp for (i = 0; i < j; i++) /* move elements 1 up */ 393*67f4addbSFrank Haverkamp s[i] = s[i + 1]; 394*67f4addbSFrank Haverkamp 395*67f4addbSFrank Haverkamp s[i].target_addr = cpu_to_be64(0); 396*67f4addbSFrank Haverkamp s[i].len = cpu_to_be32(0); 397*67f4addbSFrank Haverkamp s[i].flags = cpu_to_be32(SG_END_LIST); 398*67f4addbSFrank Haverkamp return 0; 399*67f4addbSFrank Haverkamp } 400*67f4addbSFrank Haverkamp 401*67f4addbSFrank Haverkamp void genwqe_free_sgl(struct genwqe_dev *cd, struct sg_entry *sg_list, 402*67f4addbSFrank Haverkamp dma_addr_t dma_addr, size_t size) 403*67f4addbSFrank Haverkamp { 404*67f4addbSFrank Haverkamp __genwqe_free_consistent(cd, size, sg_list, dma_addr); 405*67f4addbSFrank Haverkamp } 406*67f4addbSFrank Haverkamp 407*67f4addbSFrank Haverkamp /** 408*67f4addbSFrank Haverkamp * free_user_pages() - Give pinned pages back 409*67f4addbSFrank Haverkamp * 410*67f4addbSFrank Haverkamp * Documentation of get_user_pages is in mm/memory.c: 411*67f4addbSFrank Haverkamp * 412*67f4addbSFrank Haverkamp * If the page is written to, set_page_dirty (or set_page_dirty_lock, 413*67f4addbSFrank Haverkamp * as appropriate) must be called after the page is finished with, and 414*67f4addbSFrank Haverkamp * before put_page is called. 415*67f4addbSFrank Haverkamp * 416*67f4addbSFrank Haverkamp * FIXME Could be of use to others and might belong in the generic 417*67f4addbSFrank Haverkamp * code, if others agree. E.g. 418*67f4addbSFrank Haverkamp * ll_free_user_pages in drivers/staging/lustre/lustre/llite/rw26.c 419*67f4addbSFrank Haverkamp * ceph_put_page_vector in net/ceph/pagevec.c 420*67f4addbSFrank Haverkamp * maybe more? 421*67f4addbSFrank Haverkamp */ 422*67f4addbSFrank Haverkamp static int free_user_pages(struct page **page_list, unsigned int nr_pages, 423*67f4addbSFrank Haverkamp int dirty) 424*67f4addbSFrank Haverkamp { 425*67f4addbSFrank Haverkamp unsigned int i; 426*67f4addbSFrank Haverkamp 427*67f4addbSFrank Haverkamp for (i = 0; i < nr_pages; i++) { 428*67f4addbSFrank Haverkamp if (page_list[i] != NULL) { 429*67f4addbSFrank Haverkamp if (dirty) 430*67f4addbSFrank Haverkamp set_page_dirty_lock(page_list[i]); 431*67f4addbSFrank Haverkamp put_page(page_list[i]); 432*67f4addbSFrank Haverkamp } 433*67f4addbSFrank Haverkamp } 434*67f4addbSFrank Haverkamp return 0; 435*67f4addbSFrank Haverkamp } 436*67f4addbSFrank Haverkamp 437*67f4addbSFrank Haverkamp /** 438*67f4addbSFrank Haverkamp * genwqe_user_vmap() - Map user-space memory to virtual kernel memory 439*67f4addbSFrank Haverkamp * @cd: pointer to genwqe device 440*67f4addbSFrank Haverkamp * @m: mapping params 441*67f4addbSFrank Haverkamp * @uaddr: user virtual address 442*67f4addbSFrank Haverkamp * @size: size of memory to be mapped 443*67f4addbSFrank Haverkamp * 444*67f4addbSFrank Haverkamp * We need to think about how we could speed this up. Of course it is 445*67f4addbSFrank Haverkamp * not a good idea to do this over and over again, like we are 446*67f4addbSFrank Haverkamp * currently doing it. Nevertheless, I am curious where on the path 447*67f4addbSFrank Haverkamp * the performance is spend. Most probably within the memory 448*67f4addbSFrank Haverkamp * allocation functions, but maybe also in the DMA mapping code. 449*67f4addbSFrank Haverkamp * 450*67f4addbSFrank Haverkamp * Restrictions: The maximum size of the possible mapping currently depends 451*67f4addbSFrank Haverkamp * on the amount of memory we can get using kzalloc() for the 452*67f4addbSFrank Haverkamp * page_list and pci_alloc_consistent for the sg_list. 453*67f4addbSFrank Haverkamp * The sg_list is currently itself not scattered, which could 454*67f4addbSFrank Haverkamp * be fixed with some effort. The page_list must be split into 455*67f4addbSFrank Haverkamp * PAGE_SIZE chunks too. All that will make the complicated 456*67f4addbSFrank Haverkamp * code more complicated. 457*67f4addbSFrank Haverkamp * 458*67f4addbSFrank Haverkamp * Return: 0 if success 459*67f4addbSFrank Haverkamp */ 460*67f4addbSFrank Haverkamp int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr, 461*67f4addbSFrank Haverkamp unsigned long size, struct ddcb_requ *req) 462*67f4addbSFrank Haverkamp { 463*67f4addbSFrank Haverkamp int rc = -EINVAL; 464*67f4addbSFrank Haverkamp unsigned long data, offs; 465*67f4addbSFrank Haverkamp struct pci_dev *pci_dev = cd->pci_dev; 466*67f4addbSFrank Haverkamp 467*67f4addbSFrank Haverkamp if ((uaddr == NULL) || (size == 0)) { 468*67f4addbSFrank Haverkamp m->size = 0; /* mark unused and not added */ 469*67f4addbSFrank Haverkamp return -EINVAL; 470*67f4addbSFrank Haverkamp } 471*67f4addbSFrank Haverkamp m->u_vaddr = uaddr; 472*67f4addbSFrank Haverkamp m->size = size; 473*67f4addbSFrank Haverkamp 474*67f4addbSFrank Haverkamp /* determine space needed for page_list. */ 475*67f4addbSFrank Haverkamp data = (unsigned long)uaddr; 476*67f4addbSFrank Haverkamp offs = offset_in_page(data); 477*67f4addbSFrank Haverkamp m->nr_pages = DIV_ROUND_UP(offs + size, PAGE_SIZE); 478*67f4addbSFrank Haverkamp 479*67f4addbSFrank Haverkamp m->page_list = kcalloc(m->nr_pages, 480*67f4addbSFrank Haverkamp sizeof(struct page *) + sizeof(dma_addr_t), 481*67f4addbSFrank Haverkamp GFP_KERNEL); 482*67f4addbSFrank Haverkamp if (!m->page_list) { 483*67f4addbSFrank Haverkamp dev_err(&pci_dev->dev, "err: alloc page_list failed\n"); 484*67f4addbSFrank Haverkamp m->nr_pages = 0; 485*67f4addbSFrank Haverkamp m->u_vaddr = NULL; 486*67f4addbSFrank Haverkamp m->size = 0; /* mark unused and not added */ 487*67f4addbSFrank Haverkamp return -ENOMEM; 488*67f4addbSFrank Haverkamp } 489*67f4addbSFrank Haverkamp m->dma_list = (dma_addr_t *)(m->page_list + m->nr_pages); 490*67f4addbSFrank Haverkamp 491*67f4addbSFrank Haverkamp /* pin user pages in memory */ 492*67f4addbSFrank Haverkamp rc = get_user_pages_fast(data & PAGE_MASK, /* page aligned addr */ 493*67f4addbSFrank Haverkamp m->nr_pages, 494*67f4addbSFrank Haverkamp 1, /* write by caller */ 495*67f4addbSFrank Haverkamp m->page_list); /* ptrs to pages */ 496*67f4addbSFrank Haverkamp 497*67f4addbSFrank Haverkamp /* assumption: get_user_pages can be killed by signals. */ 498*67f4addbSFrank Haverkamp if (rc < m->nr_pages) { 499*67f4addbSFrank Haverkamp free_user_pages(m->page_list, rc, 0); 500*67f4addbSFrank Haverkamp rc = -EFAULT; 501*67f4addbSFrank Haverkamp goto fail_get_user_pages; 502*67f4addbSFrank Haverkamp } 503*67f4addbSFrank Haverkamp 504*67f4addbSFrank Haverkamp rc = genwqe_map_pages(cd, m->page_list, m->nr_pages, m->dma_list); 505*67f4addbSFrank Haverkamp if (rc != 0) 506*67f4addbSFrank Haverkamp goto fail_free_user_pages; 507*67f4addbSFrank Haverkamp 508*67f4addbSFrank Haverkamp return 0; 509*67f4addbSFrank Haverkamp 510*67f4addbSFrank Haverkamp fail_free_user_pages: 511*67f4addbSFrank Haverkamp free_user_pages(m->page_list, m->nr_pages, 0); 512*67f4addbSFrank Haverkamp 513*67f4addbSFrank Haverkamp fail_get_user_pages: 514*67f4addbSFrank Haverkamp kfree(m->page_list); 515*67f4addbSFrank Haverkamp m->page_list = NULL; 516*67f4addbSFrank Haverkamp m->dma_list = NULL; 517*67f4addbSFrank Haverkamp m->nr_pages = 0; 518*67f4addbSFrank Haverkamp m->u_vaddr = NULL; 519*67f4addbSFrank Haverkamp m->size = 0; /* mark unused and not added */ 520*67f4addbSFrank Haverkamp return rc; 521*67f4addbSFrank Haverkamp } 522*67f4addbSFrank Haverkamp 523*67f4addbSFrank Haverkamp /** 524*67f4addbSFrank Haverkamp * genwqe_user_vunmap() - Undo mapping of user-space mem to virtual kernel 525*67f4addbSFrank Haverkamp * memory 526*67f4addbSFrank Haverkamp * @cd: pointer to genwqe device 527*67f4addbSFrank Haverkamp * @m: mapping params 528*67f4addbSFrank Haverkamp */ 529*67f4addbSFrank Haverkamp int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m, 530*67f4addbSFrank Haverkamp struct ddcb_requ *req) 531*67f4addbSFrank Haverkamp { 532*67f4addbSFrank Haverkamp struct pci_dev *pci_dev = cd->pci_dev; 533*67f4addbSFrank Haverkamp 534*67f4addbSFrank Haverkamp if (!dma_mapping_used(m)) { 535*67f4addbSFrank Haverkamp dev_err(&pci_dev->dev, "[%s] err: mapping %p not used!\n", 536*67f4addbSFrank Haverkamp __func__, m); 537*67f4addbSFrank Haverkamp return -EINVAL; 538*67f4addbSFrank Haverkamp } 539*67f4addbSFrank Haverkamp 540*67f4addbSFrank Haverkamp if (m->dma_list) 541*67f4addbSFrank Haverkamp genwqe_unmap_pages(cd, m->dma_list, m->nr_pages); 542*67f4addbSFrank Haverkamp 543*67f4addbSFrank Haverkamp if (m->page_list) { 544*67f4addbSFrank Haverkamp free_user_pages(m->page_list, m->nr_pages, 1); 545*67f4addbSFrank Haverkamp 546*67f4addbSFrank Haverkamp kfree(m->page_list); 547*67f4addbSFrank Haverkamp m->page_list = NULL; 548*67f4addbSFrank Haverkamp m->dma_list = NULL; 549*67f4addbSFrank Haverkamp m->nr_pages = 0; 550*67f4addbSFrank Haverkamp } 551*67f4addbSFrank Haverkamp 552*67f4addbSFrank Haverkamp m->u_vaddr = NULL; 553*67f4addbSFrank Haverkamp m->size = 0; /* mark as unused and not added */ 554*67f4addbSFrank Haverkamp return 0; 555*67f4addbSFrank Haverkamp } 556*67f4addbSFrank Haverkamp 557*67f4addbSFrank Haverkamp /** 558*67f4addbSFrank Haverkamp * genwqe_card_type() - Get chip type SLU Configuration Register 559*67f4addbSFrank Haverkamp * @cd: pointer to the genwqe device descriptor 560*67f4addbSFrank Haverkamp * Return: 0: Altera Stratix-IV 230 561*67f4addbSFrank Haverkamp * 1: Altera Stratix-IV 530 562*67f4addbSFrank Haverkamp * 2: Altera Stratix-V A4 563*67f4addbSFrank Haverkamp * 3: Altera Stratix-V A7 564*67f4addbSFrank Haverkamp */ 565*67f4addbSFrank Haverkamp u8 genwqe_card_type(struct genwqe_dev *cd) 566*67f4addbSFrank Haverkamp { 567*67f4addbSFrank Haverkamp u64 card_type = cd->slu_unitcfg; 568*67f4addbSFrank Haverkamp return (u8)((card_type & IO_SLU_UNITCFG_TYPE_MASK) >> 20); 569*67f4addbSFrank Haverkamp } 570*67f4addbSFrank Haverkamp 571*67f4addbSFrank Haverkamp /** 572*67f4addbSFrank Haverkamp * genwqe_card_reset() - Reset the card 573*67f4addbSFrank Haverkamp * @cd: pointer to the genwqe device descriptor 574*67f4addbSFrank Haverkamp */ 575*67f4addbSFrank Haverkamp int genwqe_card_reset(struct genwqe_dev *cd) 576*67f4addbSFrank Haverkamp { 577*67f4addbSFrank Haverkamp u64 softrst; 578*67f4addbSFrank Haverkamp struct pci_dev *pci_dev = cd->pci_dev; 579*67f4addbSFrank Haverkamp 580*67f4addbSFrank Haverkamp if (!genwqe_is_privileged(cd)) 581*67f4addbSFrank Haverkamp return -ENODEV; 582*67f4addbSFrank Haverkamp 583*67f4addbSFrank Haverkamp /* new SL */ 584*67f4addbSFrank Haverkamp __genwqe_writeq(cd, IO_SLC_CFGREG_SOFTRESET, 0x1ull); 585*67f4addbSFrank Haverkamp msleep(1000); 586*67f4addbSFrank Haverkamp __genwqe_readq(cd, IO_HSU_FIR_CLR); 587*67f4addbSFrank Haverkamp __genwqe_readq(cd, IO_APP_FIR_CLR); 588*67f4addbSFrank Haverkamp __genwqe_readq(cd, IO_SLU_FIR_CLR); 589*67f4addbSFrank Haverkamp 590*67f4addbSFrank Haverkamp /* 591*67f4addbSFrank Haverkamp * Read-modify-write to preserve the stealth bits 592*67f4addbSFrank Haverkamp * 593*67f4addbSFrank Haverkamp * For SL >= 039, Stealth WE bit allows removing 594*67f4addbSFrank Haverkamp * the read-modify-wrote. 595*67f4addbSFrank Haverkamp * r-m-w may require a mask 0x3C to avoid hitting hard 596*67f4addbSFrank Haverkamp * reset again for error reset (should be 0, chicken). 597*67f4addbSFrank Haverkamp */ 598*67f4addbSFrank Haverkamp softrst = __genwqe_readq(cd, IO_SLC_CFGREG_SOFTRESET) & 0x3cull; 599*67f4addbSFrank Haverkamp __genwqe_writeq(cd, IO_SLC_CFGREG_SOFTRESET, softrst | 0x2ull); 600*67f4addbSFrank Haverkamp 601*67f4addbSFrank Haverkamp /* give ERRORRESET some time to finish */ 602*67f4addbSFrank Haverkamp msleep(50); 603*67f4addbSFrank Haverkamp 604*67f4addbSFrank Haverkamp if (genwqe_need_err_masking(cd)) { 605*67f4addbSFrank Haverkamp dev_info(&pci_dev->dev, 606*67f4addbSFrank Haverkamp "[%s] masking errors for old bitstreams\n", __func__); 607*67f4addbSFrank Haverkamp __genwqe_writeq(cd, IO_SLC_MISC_DEBUG, 0x0aull); 608*67f4addbSFrank Haverkamp } 609*67f4addbSFrank Haverkamp return 0; 610*67f4addbSFrank Haverkamp } 611*67f4addbSFrank Haverkamp 612*67f4addbSFrank Haverkamp int genwqe_read_softreset(struct genwqe_dev *cd) 613*67f4addbSFrank Haverkamp { 614*67f4addbSFrank Haverkamp u64 bitstream; 615*67f4addbSFrank Haverkamp 616*67f4addbSFrank Haverkamp if (!genwqe_is_privileged(cd)) 617*67f4addbSFrank Haverkamp return -ENODEV; 618*67f4addbSFrank Haverkamp 619*67f4addbSFrank Haverkamp bitstream = __genwqe_readq(cd, IO_SLU_BITSTREAM) & 0x1; 620*67f4addbSFrank Haverkamp cd->softreset = (bitstream == 0) ? 0x8ull : 0xcull; 621*67f4addbSFrank Haverkamp return 0; 622*67f4addbSFrank Haverkamp } 623*67f4addbSFrank Haverkamp 624*67f4addbSFrank Haverkamp /** 625*67f4addbSFrank Haverkamp * genwqe_set_interrupt_capability() - Configure MSI capability structure 626*67f4addbSFrank Haverkamp * @cd: pointer to the device 627*67f4addbSFrank Haverkamp * Return: 0 if no error 628*67f4addbSFrank Haverkamp */ 629*67f4addbSFrank Haverkamp int genwqe_set_interrupt_capability(struct genwqe_dev *cd, int count) 630*67f4addbSFrank Haverkamp { 631*67f4addbSFrank Haverkamp int rc; 632*67f4addbSFrank Haverkamp struct pci_dev *pci_dev = cd->pci_dev; 633*67f4addbSFrank Haverkamp 634*67f4addbSFrank Haverkamp rc = pci_enable_msi_block(pci_dev, count); 635*67f4addbSFrank Haverkamp if (rc == 0) 636*67f4addbSFrank Haverkamp cd->flags |= GENWQE_FLAG_MSI_ENABLED; 637*67f4addbSFrank Haverkamp return rc; 638*67f4addbSFrank Haverkamp } 639*67f4addbSFrank Haverkamp 640*67f4addbSFrank Haverkamp /** 641*67f4addbSFrank Haverkamp * genwqe_reset_interrupt_capability() - Undo genwqe_set_interrupt_capability() 642*67f4addbSFrank Haverkamp * @cd: pointer to the device 643*67f4addbSFrank Haverkamp */ 644*67f4addbSFrank Haverkamp void genwqe_reset_interrupt_capability(struct genwqe_dev *cd) 645*67f4addbSFrank Haverkamp { 646*67f4addbSFrank Haverkamp struct pci_dev *pci_dev = cd->pci_dev; 647*67f4addbSFrank Haverkamp 648*67f4addbSFrank Haverkamp if (cd->flags & GENWQE_FLAG_MSI_ENABLED) { 649*67f4addbSFrank Haverkamp pci_disable_msi(pci_dev); 650*67f4addbSFrank Haverkamp cd->flags &= ~GENWQE_FLAG_MSI_ENABLED; 651*67f4addbSFrank Haverkamp } 652*67f4addbSFrank Haverkamp } 653*67f4addbSFrank Haverkamp 654*67f4addbSFrank Haverkamp /** 655*67f4addbSFrank Haverkamp * set_reg_idx() - Fill array with data. Ignore illegal offsets. 656*67f4addbSFrank Haverkamp * @cd: card device 657*67f4addbSFrank Haverkamp * @r: debug register array 658*67f4addbSFrank Haverkamp * @i: index to desired entry 659*67f4addbSFrank Haverkamp * @m: maximum possible entries 660*67f4addbSFrank Haverkamp * @addr: addr which is read 661*67f4addbSFrank Haverkamp * @index: index in debug array 662*67f4addbSFrank Haverkamp * @val: read value 663*67f4addbSFrank Haverkamp */ 664*67f4addbSFrank Haverkamp static int set_reg_idx(struct genwqe_dev *cd, struct genwqe_reg *r, 665*67f4addbSFrank Haverkamp unsigned int *i, unsigned int m, u32 addr, u32 idx, 666*67f4addbSFrank Haverkamp u64 val) 667*67f4addbSFrank Haverkamp { 668*67f4addbSFrank Haverkamp if (WARN_ON_ONCE(*i >= m)) 669*67f4addbSFrank Haverkamp return -EFAULT; 670*67f4addbSFrank Haverkamp 671*67f4addbSFrank Haverkamp r[*i].addr = addr; 672*67f4addbSFrank Haverkamp r[*i].idx = idx; 673*67f4addbSFrank Haverkamp r[*i].val = val; 674*67f4addbSFrank Haverkamp ++*i; 675*67f4addbSFrank Haverkamp return 0; 676*67f4addbSFrank Haverkamp } 677*67f4addbSFrank Haverkamp 678*67f4addbSFrank Haverkamp static int set_reg(struct genwqe_dev *cd, struct genwqe_reg *r, 679*67f4addbSFrank Haverkamp unsigned int *i, unsigned int m, u32 addr, u64 val) 680*67f4addbSFrank Haverkamp { 681*67f4addbSFrank Haverkamp return set_reg_idx(cd, r, i, m, addr, 0, val); 682*67f4addbSFrank Haverkamp } 683*67f4addbSFrank Haverkamp 684*67f4addbSFrank Haverkamp int genwqe_read_ffdc_regs(struct genwqe_dev *cd, struct genwqe_reg *regs, 685*67f4addbSFrank Haverkamp unsigned int max_regs, int all) 686*67f4addbSFrank Haverkamp { 687*67f4addbSFrank Haverkamp unsigned int i, j, idx = 0; 688*67f4addbSFrank Haverkamp u32 ufir_addr, ufec_addr, sfir_addr, sfec_addr; 689*67f4addbSFrank Haverkamp u64 gfir, sluid, appid, ufir, ufec, sfir, sfec; 690*67f4addbSFrank Haverkamp 691*67f4addbSFrank Haverkamp /* Global FIR */ 692*67f4addbSFrank Haverkamp gfir = __genwqe_readq(cd, IO_SLC_CFGREG_GFIR); 693*67f4addbSFrank Haverkamp set_reg(cd, regs, &idx, max_regs, IO_SLC_CFGREG_GFIR, gfir); 694*67f4addbSFrank Haverkamp 695*67f4addbSFrank Haverkamp /* UnitCfg for SLU */ 696*67f4addbSFrank Haverkamp sluid = __genwqe_readq(cd, IO_SLU_UNITCFG); /* 0x00000000 */ 697*67f4addbSFrank Haverkamp set_reg(cd, regs, &idx, max_regs, IO_SLU_UNITCFG, sluid); 698*67f4addbSFrank Haverkamp 699*67f4addbSFrank Haverkamp /* UnitCfg for APP */ 700*67f4addbSFrank Haverkamp appid = __genwqe_readq(cd, IO_APP_UNITCFG); /* 0x02000000 */ 701*67f4addbSFrank Haverkamp set_reg(cd, regs, &idx, max_regs, IO_APP_UNITCFG, appid); 702*67f4addbSFrank Haverkamp 703*67f4addbSFrank Haverkamp /* Check all chip Units */ 704*67f4addbSFrank Haverkamp for (i = 0; i < GENWQE_MAX_UNITS; i++) { 705*67f4addbSFrank Haverkamp 706*67f4addbSFrank Haverkamp /* Unit FIR */ 707*67f4addbSFrank Haverkamp ufir_addr = (i << 24) | 0x008; 708*67f4addbSFrank Haverkamp ufir = __genwqe_readq(cd, ufir_addr); 709*67f4addbSFrank Haverkamp set_reg(cd, regs, &idx, max_regs, ufir_addr, ufir); 710*67f4addbSFrank Haverkamp 711*67f4addbSFrank Haverkamp /* Unit FEC */ 712*67f4addbSFrank Haverkamp ufec_addr = (i << 24) | 0x018; 713*67f4addbSFrank Haverkamp ufec = __genwqe_readq(cd, ufec_addr); 714*67f4addbSFrank Haverkamp set_reg(cd, regs, &idx, max_regs, ufec_addr, ufec); 715*67f4addbSFrank Haverkamp 716*67f4addbSFrank Haverkamp for (j = 0; j < 64; j++) { 717*67f4addbSFrank Haverkamp /* wherever there is a primary 1, read the 2ndary */ 718*67f4addbSFrank Haverkamp if (!all && (!(ufir & (1ull << j)))) 719*67f4addbSFrank Haverkamp continue; 720*67f4addbSFrank Haverkamp 721*67f4addbSFrank Haverkamp sfir_addr = (i << 24) | (0x100 + 8 * j); 722*67f4addbSFrank Haverkamp sfir = __genwqe_readq(cd, sfir_addr); 723*67f4addbSFrank Haverkamp set_reg(cd, regs, &idx, max_regs, sfir_addr, sfir); 724*67f4addbSFrank Haverkamp 725*67f4addbSFrank Haverkamp sfec_addr = (i << 24) | (0x300 + 8 * j); 726*67f4addbSFrank Haverkamp sfec = __genwqe_readq(cd, sfec_addr); 727*67f4addbSFrank Haverkamp set_reg(cd, regs, &idx, max_regs, sfec_addr, sfec); 728*67f4addbSFrank Haverkamp } 729*67f4addbSFrank Haverkamp } 730*67f4addbSFrank Haverkamp 731*67f4addbSFrank Haverkamp /* fill with invalid data until end */ 732*67f4addbSFrank Haverkamp for (i = idx; i < max_regs; i++) { 733*67f4addbSFrank Haverkamp regs[i].addr = 0xffffffff; 734*67f4addbSFrank Haverkamp regs[i].val = 0xffffffffffffffffull; 735*67f4addbSFrank Haverkamp } 736*67f4addbSFrank Haverkamp return idx; 737*67f4addbSFrank Haverkamp } 738*67f4addbSFrank Haverkamp 739*67f4addbSFrank Haverkamp /** 740*67f4addbSFrank Haverkamp * genwqe_ffdc_buff_size() - Calculates the number of dump registers 741*67f4addbSFrank Haverkamp */ 742*67f4addbSFrank Haverkamp int genwqe_ffdc_buff_size(struct genwqe_dev *cd, int uid) 743*67f4addbSFrank Haverkamp { 744*67f4addbSFrank Haverkamp int entries = 0, ring, traps, traces, trace_entries; 745*67f4addbSFrank Haverkamp u32 eevptr_addr, l_addr, d_len, d_type; 746*67f4addbSFrank Haverkamp u64 eevptr, val, addr; 747*67f4addbSFrank Haverkamp 748*67f4addbSFrank Haverkamp eevptr_addr = GENWQE_UID_OFFS(uid) | IO_EXTENDED_ERROR_POINTER; 749*67f4addbSFrank Haverkamp eevptr = __genwqe_readq(cd, eevptr_addr); 750*67f4addbSFrank Haverkamp 751*67f4addbSFrank Haverkamp if ((eevptr != 0x0) && (eevptr != -1ull)) { 752*67f4addbSFrank Haverkamp l_addr = GENWQE_UID_OFFS(uid) | eevptr; 753*67f4addbSFrank Haverkamp 754*67f4addbSFrank Haverkamp while (1) { 755*67f4addbSFrank Haverkamp val = __genwqe_readq(cd, l_addr); 756*67f4addbSFrank Haverkamp 757*67f4addbSFrank Haverkamp if ((val == 0x0) || (val == -1ull)) 758*67f4addbSFrank Haverkamp break; 759*67f4addbSFrank Haverkamp 760*67f4addbSFrank Haverkamp /* 38:24 */ 761*67f4addbSFrank Haverkamp d_len = (val & 0x0000007fff000000ull) >> 24; 762*67f4addbSFrank Haverkamp 763*67f4addbSFrank Haverkamp /* 39 */ 764*67f4addbSFrank Haverkamp d_type = (val & 0x0000008000000000ull) >> 36; 765*67f4addbSFrank Haverkamp 766*67f4addbSFrank Haverkamp if (d_type) { /* repeat */ 767*67f4addbSFrank Haverkamp entries += d_len; 768*67f4addbSFrank Haverkamp } else { /* size in bytes! */ 769*67f4addbSFrank Haverkamp entries += d_len >> 3; 770*67f4addbSFrank Haverkamp } 771*67f4addbSFrank Haverkamp 772*67f4addbSFrank Haverkamp l_addr += 8; 773*67f4addbSFrank Haverkamp } 774*67f4addbSFrank Haverkamp } 775*67f4addbSFrank Haverkamp 776*67f4addbSFrank Haverkamp for (ring = 0; ring < 8; ring++) { 777*67f4addbSFrank Haverkamp addr = GENWQE_UID_OFFS(uid) | IO_EXTENDED_DIAG_MAP(ring); 778*67f4addbSFrank Haverkamp val = __genwqe_readq(cd, addr); 779*67f4addbSFrank Haverkamp 780*67f4addbSFrank Haverkamp if ((val == 0x0ull) || (val == -1ull)) 781*67f4addbSFrank Haverkamp continue; 782*67f4addbSFrank Haverkamp 783*67f4addbSFrank Haverkamp traps = (val >> 24) & 0xff; 784*67f4addbSFrank Haverkamp traces = (val >> 16) & 0xff; 785*67f4addbSFrank Haverkamp trace_entries = val & 0xffff; 786*67f4addbSFrank Haverkamp 787*67f4addbSFrank Haverkamp entries += traps + (traces * trace_entries); 788*67f4addbSFrank Haverkamp } 789*67f4addbSFrank Haverkamp return entries; 790*67f4addbSFrank Haverkamp } 791*67f4addbSFrank Haverkamp 792*67f4addbSFrank Haverkamp /** 793*67f4addbSFrank Haverkamp * genwqe_ffdc_buff_read() - Implements LogoutExtendedErrorRegisters procedure 794*67f4addbSFrank Haverkamp */ 795*67f4addbSFrank Haverkamp int genwqe_ffdc_buff_read(struct genwqe_dev *cd, int uid, 796*67f4addbSFrank Haverkamp struct genwqe_reg *regs, unsigned int max_regs) 797*67f4addbSFrank Haverkamp { 798*67f4addbSFrank Haverkamp int i, traps, traces, trace, trace_entries, trace_entry, ring; 799*67f4addbSFrank Haverkamp unsigned int idx = 0; 800*67f4addbSFrank Haverkamp u32 eevptr_addr, l_addr, d_addr, d_len, d_type; 801*67f4addbSFrank Haverkamp u64 eevptr, e, val, addr; 802*67f4addbSFrank Haverkamp 803*67f4addbSFrank Haverkamp eevptr_addr = GENWQE_UID_OFFS(uid) | IO_EXTENDED_ERROR_POINTER; 804*67f4addbSFrank Haverkamp eevptr = __genwqe_readq(cd, eevptr_addr); 805*67f4addbSFrank Haverkamp 806*67f4addbSFrank Haverkamp if ((eevptr != 0x0) && (eevptr != 0xffffffffffffffffull)) { 807*67f4addbSFrank Haverkamp l_addr = GENWQE_UID_OFFS(uid) | eevptr; 808*67f4addbSFrank Haverkamp while (1) { 809*67f4addbSFrank Haverkamp e = __genwqe_readq(cd, l_addr); 810*67f4addbSFrank Haverkamp if ((e == 0x0) || (e == 0xffffffffffffffffull)) 811*67f4addbSFrank Haverkamp break; 812*67f4addbSFrank Haverkamp 813*67f4addbSFrank Haverkamp d_addr = (e & 0x0000000000ffffffull); /* 23:0 */ 814*67f4addbSFrank Haverkamp d_len = (e & 0x0000007fff000000ull) >> 24; /* 38:24 */ 815*67f4addbSFrank Haverkamp d_type = (e & 0x0000008000000000ull) >> 36; /* 39 */ 816*67f4addbSFrank Haverkamp d_addr |= GENWQE_UID_OFFS(uid); 817*67f4addbSFrank Haverkamp 818*67f4addbSFrank Haverkamp if (d_type) { 819*67f4addbSFrank Haverkamp for (i = 0; i < (int)d_len; i++) { 820*67f4addbSFrank Haverkamp val = __genwqe_readq(cd, d_addr); 821*67f4addbSFrank Haverkamp set_reg_idx(cd, regs, &idx, max_regs, 822*67f4addbSFrank Haverkamp d_addr, i, val); 823*67f4addbSFrank Haverkamp } 824*67f4addbSFrank Haverkamp } else { 825*67f4addbSFrank Haverkamp d_len >>= 3; /* Size in bytes! */ 826*67f4addbSFrank Haverkamp for (i = 0; i < (int)d_len; i++, d_addr += 8) { 827*67f4addbSFrank Haverkamp val = __genwqe_readq(cd, d_addr); 828*67f4addbSFrank Haverkamp set_reg_idx(cd, regs, &idx, max_regs, 829*67f4addbSFrank Haverkamp d_addr, 0, val); 830*67f4addbSFrank Haverkamp } 831*67f4addbSFrank Haverkamp } 832*67f4addbSFrank Haverkamp l_addr += 8; 833*67f4addbSFrank Haverkamp } 834*67f4addbSFrank Haverkamp } 835*67f4addbSFrank Haverkamp 836*67f4addbSFrank Haverkamp /* 837*67f4addbSFrank Haverkamp * To save time, there are only 6 traces poplulated on Uid=2, 838*67f4addbSFrank Haverkamp * Ring=1. each with iters=512. 839*67f4addbSFrank Haverkamp */ 840*67f4addbSFrank Haverkamp for (ring = 0; ring < 8; ring++) { /* 0 is fls, 1 is fds, 841*67f4addbSFrank Haverkamp 2...7 are ASI rings */ 842*67f4addbSFrank Haverkamp addr = GENWQE_UID_OFFS(uid) | IO_EXTENDED_DIAG_MAP(ring); 843*67f4addbSFrank Haverkamp val = __genwqe_readq(cd, addr); 844*67f4addbSFrank Haverkamp 845*67f4addbSFrank Haverkamp if ((val == 0x0ull) || (val == -1ull)) 846*67f4addbSFrank Haverkamp continue; 847*67f4addbSFrank Haverkamp 848*67f4addbSFrank Haverkamp traps = (val >> 24) & 0xff; /* Number of Traps */ 849*67f4addbSFrank Haverkamp traces = (val >> 16) & 0xff; /* Number of Traces */ 850*67f4addbSFrank Haverkamp trace_entries = val & 0xffff; /* Entries per trace */ 851*67f4addbSFrank Haverkamp 852*67f4addbSFrank Haverkamp /* Note: This is a combined loop that dumps both the traps */ 853*67f4addbSFrank Haverkamp /* (for the trace == 0 case) as well as the traces 1 to */ 854*67f4addbSFrank Haverkamp /* 'traces'. */ 855*67f4addbSFrank Haverkamp for (trace = 0; trace <= traces; trace++) { 856*67f4addbSFrank Haverkamp u32 diag_sel = 857*67f4addbSFrank Haverkamp GENWQE_EXTENDED_DIAG_SELECTOR(ring, trace); 858*67f4addbSFrank Haverkamp 859*67f4addbSFrank Haverkamp addr = (GENWQE_UID_OFFS(uid) | 860*67f4addbSFrank Haverkamp IO_EXTENDED_DIAG_SELECTOR); 861*67f4addbSFrank Haverkamp __genwqe_writeq(cd, addr, diag_sel); 862*67f4addbSFrank Haverkamp 863*67f4addbSFrank Haverkamp for (trace_entry = 0; 864*67f4addbSFrank Haverkamp trace_entry < (trace ? trace_entries : traps); 865*67f4addbSFrank Haverkamp trace_entry++) { 866*67f4addbSFrank Haverkamp addr = (GENWQE_UID_OFFS(uid) | 867*67f4addbSFrank Haverkamp IO_EXTENDED_DIAG_READ_MBX); 868*67f4addbSFrank Haverkamp val = __genwqe_readq(cd, addr); 869*67f4addbSFrank Haverkamp set_reg_idx(cd, regs, &idx, max_regs, addr, 870*67f4addbSFrank Haverkamp (diag_sel<<16) | trace_entry, val); 871*67f4addbSFrank Haverkamp } 872*67f4addbSFrank Haverkamp } 873*67f4addbSFrank Haverkamp } 874*67f4addbSFrank Haverkamp return 0; 875*67f4addbSFrank Haverkamp } 876*67f4addbSFrank Haverkamp 877*67f4addbSFrank Haverkamp /** 878*67f4addbSFrank Haverkamp * genwqe_write_vreg() - Write register in virtual window 879*67f4addbSFrank Haverkamp * 880*67f4addbSFrank Haverkamp * Note, these registers are only accessible to the PF through the 881*67f4addbSFrank Haverkamp * VF-window. It is not intended for the VF to access. 882*67f4addbSFrank Haverkamp */ 883*67f4addbSFrank Haverkamp int genwqe_write_vreg(struct genwqe_dev *cd, u32 reg, u64 val, int func) 884*67f4addbSFrank Haverkamp { 885*67f4addbSFrank Haverkamp __genwqe_writeq(cd, IO_PF_SLC_VIRTUAL_WINDOW, func & 0xf); 886*67f4addbSFrank Haverkamp __genwqe_writeq(cd, reg, val); 887*67f4addbSFrank Haverkamp return 0; 888*67f4addbSFrank Haverkamp } 889*67f4addbSFrank Haverkamp 890*67f4addbSFrank Haverkamp /** 891*67f4addbSFrank Haverkamp * genwqe_read_vreg() - Read register in virtual window 892*67f4addbSFrank Haverkamp * 893*67f4addbSFrank Haverkamp * Note, these registers are only accessible to the PF through the 894*67f4addbSFrank Haverkamp * VF-window. It is not intended for the VF to access. 895*67f4addbSFrank Haverkamp */ 896*67f4addbSFrank Haverkamp u64 genwqe_read_vreg(struct genwqe_dev *cd, u32 reg, int func) 897*67f4addbSFrank Haverkamp { 898*67f4addbSFrank Haverkamp __genwqe_writeq(cd, IO_PF_SLC_VIRTUAL_WINDOW, func & 0xf); 899*67f4addbSFrank Haverkamp return __genwqe_readq(cd, reg); 900*67f4addbSFrank Haverkamp } 901*67f4addbSFrank Haverkamp 902*67f4addbSFrank Haverkamp /** 903*67f4addbSFrank Haverkamp * genwqe_base_clock_frequency() - Deteremine base clock frequency of the card 904*67f4addbSFrank Haverkamp * 905*67f4addbSFrank Haverkamp * Note: From a design perspective it turned out to be a bad idea to 906*67f4addbSFrank Haverkamp * use codes here to specifiy the frequency/speed values. An old 907*67f4addbSFrank Haverkamp * driver cannot understand new codes and is therefore always a 908*67f4addbSFrank Haverkamp * problem. Better is to measure out the value or put the 909*67f4addbSFrank Haverkamp * speed/frequency directly into a register which is always a valid 910*67f4addbSFrank Haverkamp * value for old as well as for new software. 911*67f4addbSFrank Haverkamp * 912*67f4addbSFrank Haverkamp * Return: Card clock in MHz 913*67f4addbSFrank Haverkamp */ 914*67f4addbSFrank Haverkamp int genwqe_base_clock_frequency(struct genwqe_dev *cd) 915*67f4addbSFrank Haverkamp { 916*67f4addbSFrank Haverkamp u16 speed; /* MHz MHz MHz MHz */ 917*67f4addbSFrank Haverkamp static const int speed_grade[] = { 250, 200, 166, 175 }; 918*67f4addbSFrank Haverkamp 919*67f4addbSFrank Haverkamp speed = (u16)((cd->slu_unitcfg >> 28) & 0x0full); 920*67f4addbSFrank Haverkamp if (speed >= ARRAY_SIZE(speed_grade)) 921*67f4addbSFrank Haverkamp return 0; /* illegal value */ 922*67f4addbSFrank Haverkamp 923*67f4addbSFrank Haverkamp return speed_grade[speed]; 924*67f4addbSFrank Haverkamp } 925*67f4addbSFrank Haverkamp 926*67f4addbSFrank Haverkamp /** 927*67f4addbSFrank Haverkamp * genwqe_stop_traps() - Stop traps 928*67f4addbSFrank Haverkamp * 929*67f4addbSFrank Haverkamp * Before reading out the analysis data, we need to stop the traps. 930*67f4addbSFrank Haverkamp */ 931*67f4addbSFrank Haverkamp void genwqe_stop_traps(struct genwqe_dev *cd) 932*67f4addbSFrank Haverkamp { 933*67f4addbSFrank Haverkamp __genwqe_writeq(cd, IO_SLC_MISC_DEBUG_SET, 0xcull); 934*67f4addbSFrank Haverkamp } 935*67f4addbSFrank Haverkamp 936*67f4addbSFrank Haverkamp /** 937*67f4addbSFrank Haverkamp * genwqe_start_traps() - Start traps 938*67f4addbSFrank Haverkamp * 939*67f4addbSFrank Haverkamp * After having read the data, we can/must enable the traps again. 940*67f4addbSFrank Haverkamp */ 941*67f4addbSFrank Haverkamp void genwqe_start_traps(struct genwqe_dev *cd) 942*67f4addbSFrank Haverkamp { 943*67f4addbSFrank Haverkamp __genwqe_writeq(cd, IO_SLC_MISC_DEBUG_CLR, 0xcull); 944*67f4addbSFrank Haverkamp 945*67f4addbSFrank Haverkamp if (genwqe_need_err_masking(cd)) 946*67f4addbSFrank Haverkamp __genwqe_writeq(cd, IO_SLC_MISC_DEBUG, 0x0aull); 947*67f4addbSFrank Haverkamp } 948