| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Huawei HiNIC PCI Express Linux driver |
|---|
| 3 | 4 | * Copyright(c) 2017 Huawei Technologies Co., Ltd |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 7 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 10 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 11 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|---|
| 12 | | - * for more details. |
|---|
| 13 | | - * |
|---|
| 14 | 5 | */ |
|---|
| 15 | 6 | |
|---|
| 16 | 7 | #include <linux/pci.h> |
|---|
| .. | .. |
|---|
| 19 | 10 | #include <linux/io.h> |
|---|
| 20 | 11 | #include <linux/types.h> |
|---|
| 21 | 12 | #include <linux/bitops.h> |
|---|
| 13 | +#include <linux/delay.h> |
|---|
| 22 | 14 | |
|---|
| 23 | 15 | #include "hinic_hw_csr.h" |
|---|
| 24 | 16 | #include "hinic_hw_if.h" |
|---|
| .. | .. |
|---|
| 26 | 18 | #define PCIE_ATTR_ENTRY 0 |
|---|
| 27 | 19 | |
|---|
| 28 | 20 | #define VALID_MSIX_IDX(attr, msix_index) ((msix_index) < (attr)->num_irqs) |
|---|
| 21 | + |
|---|
| 22 | +#define WAIT_HWIF_READY_TIMEOUT 10000 |
|---|
| 23 | + |
|---|
| 24 | +#define HINIC_SELFTEST_RESULT 0x883C |
|---|
| 29 | 25 | |
|---|
| 30 | 26 | /** |
|---|
| 31 | 27 | * hinic_msix_attr_set - set message attribute for msix entry |
|---|
| .. | .. |
|---|
| 124 | 120 | **/ |
|---|
| 125 | 121 | void hinic_set_pf_action(struct hinic_hwif *hwif, enum hinic_pf_action action) |
|---|
| 126 | 122 | { |
|---|
| 127 | | - u32 attr5 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR5_ADDR); |
|---|
| 123 | + u32 attr5; |
|---|
| 128 | 124 | |
|---|
| 125 | + if (HINIC_IS_VF(hwif)) |
|---|
| 126 | + return; |
|---|
| 127 | + |
|---|
| 128 | + attr5 = hinic_hwif_read_reg(hwif, HINIC_CSR_FUNC_ATTR5_ADDR); |
|---|
| 129 | 129 | attr5 = HINIC_FA5_CLEAR(attr5, PF_ACTION); |
|---|
| 130 | 130 | attr5 |= HINIC_FA5_SET(action, PF_ACTION); |
|---|
| 131 | 131 | |
|---|
| .. | .. |
|---|
| 168 | 168 | hinic_hwif_write_reg(hwif, HINIC_CSR_FUNC_ATTR4_ADDR, attr4); |
|---|
| 169 | 169 | } |
|---|
| 170 | 170 | |
|---|
| 171 | +void hinic_set_msix_state(struct hinic_hwif *hwif, u16 msix_idx, |
|---|
| 172 | + enum hinic_msix_state flag) |
|---|
| 173 | +{ |
|---|
| 174 | + u32 offset = msix_idx * HINIC_PCI_MSIX_ENTRY_SIZE + |
|---|
| 175 | + HINIC_PCI_MSIX_ENTRY_VECTOR_CTRL; |
|---|
| 176 | + u32 mask_bits; |
|---|
| 177 | + |
|---|
| 178 | + mask_bits = readl(hwif->intr_regs_base + offset); |
|---|
| 179 | + mask_bits &= ~HINIC_PCI_MSIX_ENTRY_CTRL_MASKBIT; |
|---|
| 180 | + |
|---|
| 181 | + if (flag) |
|---|
| 182 | + mask_bits |= HINIC_PCI_MSIX_ENTRY_CTRL_MASKBIT; |
|---|
| 183 | + |
|---|
| 184 | + writel(mask_bits, hwif->intr_regs_base + offset); |
|---|
| 185 | +} |
|---|
| 186 | + |
|---|
| 171 | 187 | /** |
|---|
| 172 | 188 | * hwif_ready - test if the HW is ready for use |
|---|
| 173 | 189 | * @hwif: the HW interface of a pci function device |
|---|
| .. | .. |
|---|
| 176 | 192 | **/ |
|---|
| 177 | 193 | static int hwif_ready(struct hinic_hwif *hwif) |
|---|
| 178 | 194 | { |
|---|
| 179 | | - struct pci_dev *pdev = hwif->pdev; |
|---|
| 180 | 195 | u32 addr, attr1; |
|---|
| 181 | 196 | |
|---|
| 182 | 197 | addr = HINIC_CSR_FUNC_ATTR1_ADDR; |
|---|
| 183 | 198 | attr1 = hinic_hwif_read_reg(hwif, addr); |
|---|
| 184 | 199 | |
|---|
| 185 | | - if (!HINIC_FA1_GET(attr1, INIT_STATUS)) { |
|---|
| 186 | | - dev_err(&pdev->dev, "hwif status is not ready\n"); |
|---|
| 187 | | - return -EFAULT; |
|---|
| 200 | + if (!HINIC_FA1_GET(attr1, MGMT_INIT_STATUS)) |
|---|
| 201 | + return -EBUSY; |
|---|
| 202 | + |
|---|
| 203 | + if (HINIC_IS_VF(hwif)) { |
|---|
| 204 | + if (!HINIC_FA1_GET(attr1, PF_INIT_STATUS)) |
|---|
| 205 | + return -EBUSY; |
|---|
| 188 | 206 | } |
|---|
| 189 | 207 | |
|---|
| 190 | 208 | return 0; |
|---|
| 209 | +} |
|---|
| 210 | + |
|---|
| 211 | +static int wait_hwif_ready(struct hinic_hwif *hwif) |
|---|
| 212 | +{ |
|---|
| 213 | + unsigned long timeout = 0; |
|---|
| 214 | + |
|---|
| 215 | + do { |
|---|
| 216 | + if (!hwif_ready(hwif)) |
|---|
| 217 | + return 0; |
|---|
| 218 | + |
|---|
| 219 | + usleep_range(999, 1000); |
|---|
| 220 | + timeout++; |
|---|
| 221 | + } while (timeout <= WAIT_HWIF_READY_TIMEOUT); |
|---|
| 222 | + |
|---|
| 223 | + dev_err(&hwif->pdev->dev, "Wait for hwif timeout\n"); |
|---|
| 224 | + |
|---|
| 225 | + return -EBUSY; |
|---|
| 191 | 226 | } |
|---|
| 192 | 227 | |
|---|
| 193 | 228 | /** |
|---|
| .. | .. |
|---|
| 195 | 230 | * @hwif: the HW interface of a pci function device |
|---|
| 196 | 231 | * @attr0: the first attribute that was read from the hw |
|---|
| 197 | 232 | * @attr1: the second attribute that was read from the hw |
|---|
| 233 | + * @attr2: the third attribute that was read from the hw |
|---|
| 198 | 234 | **/ |
|---|
| 199 | | -static void set_hwif_attr(struct hinic_hwif *hwif, u32 attr0, u32 attr1) |
|---|
| 235 | +static void set_hwif_attr(struct hinic_hwif *hwif, u32 attr0, u32 attr1, |
|---|
| 236 | + u32 attr2) |
|---|
| 200 | 237 | { |
|---|
| 201 | 238 | hwif->attr.func_idx = HINIC_FA0_GET(attr0, FUNC_IDX); |
|---|
| 202 | 239 | hwif->attr.pf_idx = HINIC_FA0_GET(attr0, PF_IDX); |
|---|
| .. | .. |
|---|
| 207 | 244 | hwif->attr.num_ceqs = BIT(HINIC_FA1_GET(attr1, CEQS_PER_FUNC)); |
|---|
| 208 | 245 | hwif->attr.num_irqs = BIT(HINIC_FA1_GET(attr1, IRQS_PER_FUNC)); |
|---|
| 209 | 246 | hwif->attr.num_dma_attr = BIT(HINIC_FA1_GET(attr1, DMA_ATTR_PER_FUNC)); |
|---|
| 247 | + hwif->attr.global_vf_id_of_pf = HINIC_FA2_GET(attr2, |
|---|
| 248 | + GLOBAL_VF_ID_OF_PF); |
|---|
| 210 | 249 | } |
|---|
| 211 | 250 | |
|---|
| 212 | 251 | /** |
|---|
| .. | .. |
|---|
| 215 | 254 | **/ |
|---|
| 216 | 255 | static void read_hwif_attr(struct hinic_hwif *hwif) |
|---|
| 217 | 256 | { |
|---|
| 218 | | - u32 addr, attr0, attr1; |
|---|
| 257 | + u32 addr, attr0, attr1, attr2; |
|---|
| 219 | 258 | |
|---|
| 220 | 259 | addr = HINIC_CSR_FUNC_ATTR0_ADDR; |
|---|
| 221 | 260 | attr0 = hinic_hwif_read_reg(hwif, addr); |
|---|
| .. | .. |
|---|
| 223 | 262 | addr = HINIC_CSR_FUNC_ATTR1_ADDR; |
|---|
| 224 | 263 | attr1 = hinic_hwif_read_reg(hwif, addr); |
|---|
| 225 | 264 | |
|---|
| 226 | | - set_hwif_attr(hwif, attr0, attr1); |
|---|
| 265 | + addr = HINIC_CSR_FUNC_ATTR2_ADDR; |
|---|
| 266 | + attr2 = hinic_hwif_read_reg(hwif, addr); |
|---|
| 267 | + |
|---|
| 268 | + set_hwif_attr(hwif, attr0, attr1, attr2); |
|---|
| 227 | 269 | } |
|---|
| 228 | 270 | |
|---|
| 229 | 271 | /** |
|---|
| .. | .. |
|---|
| 302 | 344 | HINIC_PCIE_SNOOP, HINIC_PCIE_TPH_DISABLE); |
|---|
| 303 | 345 | } |
|---|
| 304 | 346 | |
|---|
| 347 | +u16 hinic_glb_pf_vf_offset(struct hinic_hwif *hwif) |
|---|
| 348 | +{ |
|---|
| 349 | + if (!hwif) |
|---|
| 350 | + return 0; |
|---|
| 351 | + |
|---|
| 352 | + return hwif->attr.global_vf_id_of_pf; |
|---|
| 353 | +} |
|---|
| 354 | + |
|---|
| 355 | +u16 hinic_global_func_id_hw(struct hinic_hwif *hwif) |
|---|
| 356 | +{ |
|---|
| 357 | + u32 addr, attr0; |
|---|
| 358 | + |
|---|
| 359 | + addr = HINIC_CSR_FUNC_ATTR0_ADDR; |
|---|
| 360 | + attr0 = hinic_hwif_read_reg(hwif, addr); |
|---|
| 361 | + |
|---|
| 362 | + return HINIC_FA0_GET(attr0, FUNC_IDX); |
|---|
| 363 | +} |
|---|
| 364 | + |
|---|
| 365 | +u16 hinic_pf_id_of_vf_hw(struct hinic_hwif *hwif) |
|---|
| 366 | +{ |
|---|
| 367 | + u32 addr, attr0; |
|---|
| 368 | + |
|---|
| 369 | + addr = HINIC_CSR_FUNC_ATTR0_ADDR; |
|---|
| 370 | + attr0 = hinic_hwif_read_reg(hwif, addr); |
|---|
| 371 | + |
|---|
| 372 | + return HINIC_FA0_GET(attr0, PF_IDX); |
|---|
| 373 | +} |
|---|
| 374 | + |
|---|
| 375 | +static void __print_selftest_reg(struct hinic_hwif *hwif) |
|---|
| 376 | +{ |
|---|
| 377 | + u32 addr, attr0, attr1; |
|---|
| 378 | + |
|---|
| 379 | + addr = HINIC_CSR_FUNC_ATTR1_ADDR; |
|---|
| 380 | + attr1 = hinic_hwif_read_reg(hwif, addr); |
|---|
| 381 | + |
|---|
| 382 | + if (attr1 == HINIC_PCIE_LINK_DOWN) { |
|---|
| 383 | + dev_err(&hwif->pdev->dev, "PCIE is link down\n"); |
|---|
| 384 | + return; |
|---|
| 385 | + } |
|---|
| 386 | + |
|---|
| 387 | + addr = HINIC_CSR_FUNC_ATTR0_ADDR; |
|---|
| 388 | + attr0 = hinic_hwif_read_reg(hwif, addr); |
|---|
| 389 | + if (HINIC_FA0_GET(attr0, FUNC_TYPE) != HINIC_VF && |
|---|
| 390 | + !HINIC_FA0_GET(attr0, PCI_INTF_IDX)) |
|---|
| 391 | + dev_err(&hwif->pdev->dev, "Selftest reg: 0x%08x\n", |
|---|
| 392 | + hinic_hwif_read_reg(hwif, HINIC_SELFTEST_RESULT)); |
|---|
| 393 | +} |
|---|
| 394 | + |
|---|
| 305 | 395 | /** |
|---|
| 306 | 396 | * hinic_init_hwif - initialize the hw interface |
|---|
| 307 | 397 | * @hwif: the HW interface of a pci function device |
|---|
| .. | .. |
|---|
| 321 | 411 | return -ENOMEM; |
|---|
| 322 | 412 | } |
|---|
| 323 | 413 | |
|---|
| 324 | | - err = hwif_ready(hwif); |
|---|
| 414 | + hwif->intr_regs_base = pci_ioremap_bar(pdev, HINIC_PCI_INTR_REGS_BAR); |
|---|
| 415 | + if (!hwif->intr_regs_base) { |
|---|
| 416 | + dev_err(&pdev->dev, "Failed to map configuration regs\n"); |
|---|
| 417 | + err = -ENOMEM; |
|---|
| 418 | + goto err_map_intr_bar; |
|---|
| 419 | + } |
|---|
| 420 | + |
|---|
| 421 | + err = wait_hwif_ready(hwif); |
|---|
| 325 | 422 | if (err) { |
|---|
| 326 | 423 | dev_err(&pdev->dev, "HW interface is not ready\n"); |
|---|
| 424 | + __print_selftest_reg(hwif); |
|---|
| 327 | 425 | goto err_hwif_ready; |
|---|
| 328 | 426 | } |
|---|
| 329 | 427 | |
|---|
| .. | .. |
|---|
| 337 | 435 | return 0; |
|---|
| 338 | 436 | |
|---|
| 339 | 437 | err_hwif_ready: |
|---|
| 438 | + iounmap(hwif->intr_regs_base); |
|---|
| 439 | + |
|---|
| 440 | +err_map_intr_bar: |
|---|
| 340 | 441 | iounmap(hwif->cfg_regs_bar); |
|---|
| 442 | + |
|---|
| 341 | 443 | return err; |
|---|
| 342 | 444 | } |
|---|
| 343 | 445 | |
|---|
| .. | .. |
|---|
| 347 | 449 | **/ |
|---|
| 348 | 450 | void hinic_free_hwif(struct hinic_hwif *hwif) |
|---|
| 349 | 451 | { |
|---|
| 452 | + iounmap(hwif->intr_regs_base); |
|---|
| 350 | 453 | iounmap(hwif->cfg_regs_bar); |
|---|
| 351 | 454 | } |
|---|