.. | .. |
---|
| 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 | } |
---|