Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

csiostor: Segregate T4 adapter operations.

This patch separates T4 adapter operations into a new file.

Signed-off-by: Arvind Bhushan <arvindb@chelsio.com>
Signed-off-by: Naresh Kumar Inna <naresh@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Arvind Bhushan and committed by
David S. Miller
3ac93660 9919d5bd

+403
+403
drivers/scsi/csiostor/csio_hw_t4.c
··· 1 + /* 2 + * This file is part of the Chelsio FCoE driver for Linux. 3 + * 4 + * Copyright (c) 2008-2013 Chelsio Communications, Inc. All rights reserved. 5 + * 6 + * This software is available to you under a choice of one of two 7 + * licenses. You may choose to be licensed under the terms of the GNU 8 + * General Public License (GPL) Version 2, available from the file 9 + * OpenIB.org BSD license below: 10 + * 11 + * Redistribution and use in source and binary forms, with or 12 + * without modification, are permitted provided that the following 13 + * conditions are met: 14 + * 15 + * - Redistributions of source code must retain the above 16 + * copyright notice, this list of conditions and the following 17 + * - Redistributions in binary form must reproduce the above 18 + * copyright notice, this list of conditions and the following 19 + * disclaimer in the documentation and/or other materials 20 + * provided with the distribution. 21 + * 22 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 26 + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 27 + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 28 + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 + * SOFTWARE. 30 + */ 31 + 32 + #include "csio_hw.h" 33 + #include "csio_init.h" 34 + 35 + /* 36 + * Return the specified PCI-E Configuration Space register from our Physical 37 + * Function. We try first via a Firmware LDST Command since we prefer to let 38 + * the firmware own all of these registers, but if that fails we go for it 39 + * directly ourselves. 40 + */ 41 + static uint32_t 42 + csio_t4_read_pcie_cfg4(struct csio_hw *hw, int reg) 43 + { 44 + u32 val = 0; 45 + struct csio_mb *mbp; 46 + int rv; 47 + struct fw_ldst_cmd *ldst_cmd; 48 + 49 + mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC); 50 + if (!mbp) { 51 + CSIO_INC_STATS(hw, n_err_nomem); 52 + pci_read_config_dword(hw->pdev, reg, &val); 53 + return val; 54 + } 55 + 56 + csio_mb_ldst(hw, mbp, CSIO_MB_DEFAULT_TMO, reg); 57 + rv = csio_mb_issue(hw, mbp); 58 + 59 + /* 60 + * If the LDST Command suucceeded, exctract the returned register 61 + * value. Otherwise read it directly ourself. 62 + */ 63 + if (rv == 0) { 64 + ldst_cmd = (struct fw_ldst_cmd *)(mbp->mb); 65 + val = ntohl(ldst_cmd->u.pcie.data[0]); 66 + } else 67 + pci_read_config_dword(hw->pdev, reg, &val); 68 + 69 + mempool_free(mbp, hw->mb_mempool); 70 + 71 + return val; 72 + } 73 + 74 + static int 75 + csio_t4_set_mem_win(struct csio_hw *hw, uint32_t win) 76 + { 77 + u32 bar0; 78 + u32 mem_win_base; 79 + 80 + /* 81 + * Truncation intentional: we only read the bottom 32-bits of the 82 + * 64-bit BAR0/BAR1 ... We use the hardware backdoor mechanism to 83 + * read BAR0 instead of using pci_resource_start() because we could be 84 + * operating from within a Virtual Machine which is trapping our 85 + * accesses to our Configuration Space and we need to set up the PCI-E 86 + * Memory Window decoders with the actual addresses which will be 87 + * coming across the PCI-E link. 88 + */ 89 + bar0 = csio_t4_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0); 90 + bar0 &= PCI_BASE_ADDRESS_MEM_MASK; 91 + 92 + mem_win_base = bar0 + MEMWIN_BASE; 93 + 94 + /* 95 + * Set up memory window for accessing adapter memory ranges. (Read 96 + * back MA register to ensure that changes propagate before we attempt 97 + * to use the new values.) 98 + */ 99 + csio_wr_reg32(hw, mem_win_base | BIR(0) | 100 + WINDOW(ilog2(MEMWIN_APERTURE) - 10), 101 + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win)); 102 + csio_rd_reg32(hw, 103 + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win)); 104 + return 0; 105 + } 106 + 107 + /* 108 + * Interrupt handler for the PCIE module. 109 + */ 110 + static void 111 + csio_t4_pcie_intr_handler(struct csio_hw *hw) 112 + { 113 + static struct intr_info sysbus_intr_info[] = { 114 + { RNPP, "RXNP array parity error", -1, 1 }, 115 + { RPCP, "RXPC array parity error", -1, 1 }, 116 + { RCIP, "RXCIF array parity error", -1, 1 }, 117 + { RCCP, "Rx completions control array parity error", -1, 1 }, 118 + { RFTP, "RXFT array parity error", -1, 1 }, 119 + { 0, NULL, 0, 0 } 120 + }; 121 + static struct intr_info pcie_port_intr_info[] = { 122 + { TPCP, "TXPC array parity error", -1, 1 }, 123 + { TNPP, "TXNP array parity error", -1, 1 }, 124 + { TFTP, "TXFT array parity error", -1, 1 }, 125 + { TCAP, "TXCA array parity error", -1, 1 }, 126 + { TCIP, "TXCIF array parity error", -1, 1 }, 127 + { RCAP, "RXCA array parity error", -1, 1 }, 128 + { OTDD, "outbound request TLP discarded", -1, 1 }, 129 + { RDPE, "Rx data parity error", -1, 1 }, 130 + { TDUE, "Tx uncorrectable data error", -1, 1 }, 131 + { 0, NULL, 0, 0 } 132 + }; 133 + 134 + static struct intr_info pcie_intr_info[] = { 135 + { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 }, 136 + { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 }, 137 + { MSIDATAPERR, "MSI data parity error", -1, 1 }, 138 + { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 }, 139 + { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 }, 140 + { MSIXDATAPERR, "MSI-X data parity error", -1, 1 }, 141 + { MSIXDIPERR, "MSI-X DI parity error", -1, 1 }, 142 + { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 }, 143 + { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 }, 144 + { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 }, 145 + { CCNTPERR, "PCI CMD channel count parity error", -1, 1 }, 146 + { CREQPERR, "PCI CMD channel request parity error", -1, 1 }, 147 + { CRSPPERR, "PCI CMD channel response parity error", -1, 1 }, 148 + { DCNTPERR, "PCI DMA channel count parity error", -1, 1 }, 149 + { DREQPERR, "PCI DMA channel request parity error", -1, 1 }, 150 + { DRSPPERR, "PCI DMA channel response parity error", -1, 1 }, 151 + { HCNTPERR, "PCI HMA channel count parity error", -1, 1 }, 152 + { HREQPERR, "PCI HMA channel request parity error", -1, 1 }, 153 + { HRSPPERR, "PCI HMA channel response parity error", -1, 1 }, 154 + { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 }, 155 + { FIDPERR, "PCI FID parity error", -1, 1 }, 156 + { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 }, 157 + { MATAGPERR, "PCI MA tag parity error", -1, 1 }, 158 + { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 }, 159 + { RXCPLPERR, "PCI Rx completion parity error", -1, 1 }, 160 + { RXWRPERR, "PCI Rx write parity error", -1, 1 }, 161 + { RPLPERR, "PCI replay buffer parity error", -1, 1 }, 162 + { PCIESINT, "PCI core secondary fault", -1, 1 }, 163 + { PCIEPINT, "PCI core primary fault", -1, 1 }, 164 + { UNXSPLCPLERR, "PCI unexpected split completion error", -1, 165 + 0 }, 166 + { 0, NULL, 0, 0 } 167 + }; 168 + 169 + int fat; 170 + fat = csio_handle_intr_status(hw, 171 + PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS, 172 + sysbus_intr_info) + 173 + csio_handle_intr_status(hw, 174 + PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS, 175 + pcie_port_intr_info) + 176 + csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info); 177 + if (fat) 178 + csio_hw_fatal_err(hw); 179 + } 180 + 181 + /* 182 + * csio_t4_flash_cfg_addr - return the address of the flash configuration file 183 + * @hw: the HW module 184 + * 185 + * Return the address within the flash where the Firmware Configuration 186 + * File is stored. 187 + */ 188 + static unsigned int 189 + csio_t4_flash_cfg_addr(struct csio_hw *hw) 190 + { 191 + return FLASH_CFG_OFFSET; 192 + } 193 + 194 + /* 195 + * csio_t4_mc_read - read from MC through backdoor accesses 196 + * @hw: the hw module 197 + * @idx: not used for T4 adapter 198 + * @addr: address of first byte requested 199 + * @data: 64 bytes of data containing the requested address 200 + * @ecc: where to store the corresponding 64-bit ECC word 201 + * 202 + * Read 64 bytes of data from MC starting at a 64-byte-aligned address 203 + * that covers the requested address @addr. If @parity is not %NULL it 204 + * is assigned the 64-bit ECC word for the read data. 205 + */ 206 + static int 207 + csio_t4_mc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data, 208 + uint64_t *ecc) 209 + { 210 + int i; 211 + 212 + if (csio_rd_reg32(hw, MC_BIST_CMD) & START_BIST) 213 + return -EBUSY; 214 + csio_wr_reg32(hw, addr & ~0x3fU, MC_BIST_CMD_ADDR); 215 + csio_wr_reg32(hw, 64, MC_BIST_CMD_LEN); 216 + csio_wr_reg32(hw, 0xc, MC_BIST_DATA_PATTERN); 217 + csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1), 218 + MC_BIST_CMD); 219 + i = csio_hw_wait_op_done_val(hw, MC_BIST_CMD, START_BIST, 220 + 0, 10, 1, NULL); 221 + if (i) 222 + return i; 223 + 224 + #define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i) 225 + 226 + for (i = 15; i >= 0; i--) 227 + *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i))); 228 + if (ecc) 229 + *ecc = csio_rd_reg64(hw, MC_DATA(16)); 230 + #undef MC_DATA 231 + return 0; 232 + } 233 + 234 + /* 235 + * csio_t4_edc_read - read from EDC through backdoor accesses 236 + * @hw: the hw module 237 + * @idx: which EDC to access 238 + * @addr: address of first byte requested 239 + * @data: 64 bytes of data containing the requested address 240 + * @ecc: where to store the corresponding 64-bit ECC word 241 + * 242 + * Read 64 bytes of data from EDC starting at a 64-byte-aligned address 243 + * that covers the requested address @addr. If @parity is not %NULL it 244 + * is assigned the 64-bit ECC word for the read data. 245 + */ 246 + static int 247 + csio_t4_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data, 248 + uint64_t *ecc) 249 + { 250 + int i; 251 + 252 + idx *= EDC_STRIDE; 253 + if (csio_rd_reg32(hw, EDC_BIST_CMD + idx) & START_BIST) 254 + return -EBUSY; 255 + csio_wr_reg32(hw, addr & ~0x3fU, EDC_BIST_CMD_ADDR + idx); 256 + csio_wr_reg32(hw, 64, EDC_BIST_CMD_LEN + idx); 257 + csio_wr_reg32(hw, 0xc, EDC_BIST_DATA_PATTERN + idx); 258 + csio_wr_reg32(hw, BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST, 259 + EDC_BIST_CMD + idx); 260 + i = csio_hw_wait_op_done_val(hw, EDC_BIST_CMD + idx, START_BIST, 261 + 0, 10, 1, NULL); 262 + if (i) 263 + return i; 264 + 265 + #define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx) 266 + 267 + for (i = 15; i >= 0; i--) 268 + *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i))); 269 + if (ecc) 270 + *ecc = csio_rd_reg64(hw, EDC_DATA(16)); 271 + #undef EDC_DATA 272 + return 0; 273 + } 274 + 275 + /* 276 + * csio_t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window 277 + * @hw: the csio_hw 278 + * @win: PCI-E memory Window to use 279 + * @mtype: memory type: MEM_EDC0, MEM_EDC1, MEM_MC0 (or MEM_MC) or MEM_MC1 280 + * @addr: address within indicated memory type 281 + * @len: amount of memory to transfer 282 + * @buf: host memory buffer 283 + * @dir: direction of transfer 1 => read, 0 => write 284 + * 285 + * Reads/writes an [almost] arbitrary memory region in the firmware: the 286 + * firmware memory address, length and host buffer must be aligned on 287 + * 32-bit boudaries. The memory is transferred as a raw byte sequence 288 + * from/to the firmware's memory. If this memory contains data 289 + * structures which contain multi-byte integers, it's the callers 290 + * responsibility to perform appropriate byte order conversions. 291 + */ 292 + static int 293 + csio_t4_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr, 294 + u32 len, uint32_t *buf, int dir) 295 + { 296 + u32 pos, start, offset, memoffset, bar0; 297 + u32 edc_size, mc_size, mem_reg, mem_aperture, mem_base; 298 + 299 + /* 300 + * Argument sanity checks ... 301 + */ 302 + if ((addr & 0x3) || (len & 0x3)) 303 + return -EINVAL; 304 + 305 + /* Offset into the region of memory which is being accessed 306 + * MEM_EDC0 = 0 307 + * MEM_EDC1 = 1 308 + * MEM_MC = 2 -- T4 309 + */ 310 + edc_size = EDRAM_SIZE_GET(csio_rd_reg32(hw, MA_EDRAM0_BAR)); 311 + if (mtype != MEM_MC1) 312 + memoffset = (mtype * (edc_size * 1024 * 1024)); 313 + else { 314 + mc_size = EXT_MEM_SIZE_GET(csio_rd_reg32(hw, 315 + MA_EXT_MEMORY_BAR)); 316 + memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024; 317 + } 318 + 319 + /* Determine the PCIE_MEM_ACCESS_OFFSET */ 320 + addr = addr + memoffset; 321 + 322 + /* 323 + * Each PCI-E Memory Window is programmed with a window size -- or 324 + * "aperture" -- which controls the granularity of its mapping onto 325 + * adapter memory. We need to grab that aperture in order to know 326 + * how to use the specified window. The window is also programmed 327 + * with the base address of the Memory Window in BAR0's address 328 + * space. For T4 this is an absolute PCI-E Bus Address. For T5 329 + * the address is relative to BAR0. 330 + */ 331 + mem_reg = csio_rd_reg32(hw, 332 + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win)); 333 + mem_aperture = 1 << (WINDOW(mem_reg) + 10); 334 + mem_base = GET_PCIEOFST(mem_reg) << 10; 335 + 336 + bar0 = csio_t4_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0); 337 + bar0 &= PCI_BASE_ADDRESS_MEM_MASK; 338 + mem_base -= bar0; 339 + 340 + start = addr & ~(mem_aperture-1); 341 + offset = addr - start; 342 + 343 + csio_dbg(hw, "csio_t4_memory_rw: mem_reg: 0x%x, mem_aperture: 0x%x\n", 344 + mem_reg, mem_aperture); 345 + csio_dbg(hw, "csio_t4_memory_rw: mem_base: 0x%x, mem_offset: 0x%x\n", 346 + mem_base, memoffset); 347 + csio_dbg(hw, "csio_t4_memory_rw: bar0: 0x%x, start:0x%x, offset:0x%x\n", 348 + bar0, start, offset); 349 + csio_dbg(hw, "csio_t4_memory_rw: mtype: %d, addr: 0x%x, len: %d\n", 350 + mtype, addr, len); 351 + 352 + for (pos = start; len > 0; pos += mem_aperture, offset = 0) { 353 + /* 354 + * Move PCI-E Memory Window to our current transfer 355 + * position. Read it back to ensure that changes propagate 356 + * before we attempt to use the new value. 357 + */ 358 + csio_wr_reg32(hw, pos, 359 + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win)); 360 + csio_rd_reg32(hw, 361 + PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win)); 362 + 363 + while (offset < mem_aperture && len > 0) { 364 + if (dir) 365 + *buf++ = csio_rd_reg32(hw, mem_base + offset); 366 + else 367 + csio_wr_reg32(hw, *buf++, mem_base + offset); 368 + 369 + offset += sizeof(__be32); 370 + len -= sizeof(__be32); 371 + } 372 + } 373 + return 0; 374 + } 375 + 376 + /* 377 + * csio_t4_dfs_create_ext_mem - setup debugfs for MC to read the values 378 + * @hw: the csio_hw 379 + * 380 + * This function creates files in the debugfs with external memory region MC. 381 + */ 382 + static void 383 + csio_t4_dfs_create_ext_mem(struct csio_hw *hw) 384 + { 385 + u32 size; 386 + int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE); 387 + if (i & EXT_MEM_ENABLE) { 388 + size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR); 389 + csio_add_debugfs_mem(hw, "mc", MEM_MC, 390 + EXT_MEM_SIZE_GET(size)); 391 + } 392 + } 393 + 394 + /* T4 adapter specific function */ 395 + struct csio_hw_chip_ops t4_ops = { 396 + .chip_set_mem_win = csio_t4_set_mem_win, 397 + .chip_pcie_intr_handler = csio_t4_pcie_intr_handler, 398 + .chip_flash_cfg_addr = csio_t4_flash_cfg_addr, 399 + .chip_mc_read = csio_t4_mc_read, 400 + .chip_edc_read = csio_t4_edc_read, 401 + .chip_memory_rw = csio_t4_memory_rw, 402 + .chip_dfs_create_ext_mem = csio_t4_dfs_create_ext_mem, 403 + };