xref: /linux/drivers/scsi/bfa/bfa_hw_cb.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
4  * Copyright (c) 2014- QLogic Corporation.
5  * All rights reserved
6  * www.qlogic.com
7  *
8  * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
9  */
10 
11 #include "bfad_drv.h"
12 #include "bfa_modules.h"
13 #include "bfi_reg.h"
14 
15 void
bfa_hwcb_reginit(struct bfa_s * bfa)16 bfa_hwcb_reginit(struct bfa_s *bfa)
17 {
18 	struct bfa_iocfc_regs_s	*bfa_regs = &bfa->iocfc.bfa_regs;
19 	void __iomem *kva = bfa_ioc_bar0(&bfa->ioc);
20 	int	fn = bfa_ioc_pcifn(&bfa->ioc);
21 
22 	if (fn == 0) {
23 		bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS);
24 		bfa_regs->intr_mask   = (kva + HOSTFN0_INT_MSK);
25 	} else {
26 		bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS);
27 		bfa_regs->intr_mask   = (kva + HOSTFN1_INT_MSK);
28 	}
29 }
30 
31 static void
bfa_hwcb_reqq_ack_msix(struct bfa_s * bfa,int reqq)32 bfa_hwcb_reqq_ack_msix(struct bfa_s *bfa, int reqq)
33 {
34 	writel(__HFN_INT_CPE_Q0 << CPE_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), reqq),
35 			bfa->iocfc.bfa_regs.intr_status);
36 }
37 
38 /*
39  * Actions to respond RME Interrupt for Crossbow ASIC:
40  * - Write 1 to Interrupt Status register
41  *              INTX - done in bfa_intx()
42  *              MSIX - done in bfa_hwcb_rspq_ack_msix()
43  * - Update CI (only if new CI)
44  */
45 static void
bfa_hwcb_rspq_ack_msix(struct bfa_s * bfa,int rspq,u32 ci)46 bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq, u32 ci)
47 {
48 	writel(__HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq),
49 		bfa->iocfc.bfa_regs.intr_status);
50 
51 	if (bfa_rspq_ci(bfa, rspq) == ci)
52 		return;
53 
54 	bfa_rspq_ci(bfa, rspq) = ci;
55 	writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
56 }
57 
58 void
bfa_hwcb_rspq_ack(struct bfa_s * bfa,int rspq,u32 ci)59 bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci)
60 {
61 	if (bfa_rspq_ci(bfa, rspq) == ci)
62 		return;
63 
64 	bfa_rspq_ci(bfa, rspq) = ci;
65 	writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]);
66 }
67 
68 void
bfa_hwcb_msix_getvecs(struct bfa_s * bfa,u32 * msix_vecs_bmap,u32 * num_vecs,u32 * max_vec_bit)69 bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
70 		 u32 *num_vecs, u32 *max_vec_bit)
71 {
72 #define __HFN_NUMINTS	13
73 	if (bfa_ioc_pcifn(&bfa->ioc) == 0) {
74 		*msix_vecs_bmap = (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 |
75 				   __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 |
76 				   __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 |
77 				   __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 |
78 				   __HFN_INT_MBOX_LPU0);
79 		*max_vec_bit = __HFN_INT_MBOX_LPU0;
80 	} else {
81 		*msix_vecs_bmap = (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 |
82 				   __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 |
83 				   __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 |
84 				   __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 |
85 				   __HFN_INT_MBOX_LPU1);
86 		*max_vec_bit = __HFN_INT_MBOX_LPU1;
87 	}
88 
89 	*msix_vecs_bmap |= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
90 			    __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS);
91 	*num_vecs = __HFN_NUMINTS;
92 }
93 
94 /*
95  * Dummy interrupt handler for handling spurious interrupts.
96  */
97 static void
bfa_hwcb_msix_dummy(struct bfa_s * bfa,int vec)98 bfa_hwcb_msix_dummy(struct bfa_s *bfa, int vec)
99 {
100 }
101 
102 /*
103  * No special setup required for crossbow -- vector assignments are implicit.
104  */
105 void
bfa_hwcb_msix_init(struct bfa_s * bfa,int nvecs)106 bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs)
107 {
108 	WARN_ON((nvecs != 1) && (nvecs != __HFN_NUMINTS));
109 
110 	bfa->msix.nvecs = nvecs;
111 	bfa_hwcb_msix_uninstall(bfa);
112 }
113 
114 void
bfa_hwcb_msix_ctrl_install(struct bfa_s * bfa)115 bfa_hwcb_msix_ctrl_install(struct bfa_s *bfa)
116 {
117 	int i;
118 
119 	if (bfa->msix.nvecs == 0)
120 		return;
121 
122 	if (bfa->msix.nvecs == 1) {
123 		for (i = BFI_MSIX_CPE_QMIN_CB; i < BFI_MSIX_CB_MAX; i++)
124 			bfa->msix.handler[i] = bfa_msix_all;
125 		return;
126 	}
127 
128 	for (i = BFI_MSIX_RME_QMAX_CB+1; i < BFI_MSIX_CB_MAX; i++)
129 		bfa->msix.handler[i] = bfa_msix_lpu_err;
130 }
131 
132 void
bfa_hwcb_msix_queue_install(struct bfa_s * bfa)133 bfa_hwcb_msix_queue_install(struct bfa_s *bfa)
134 {
135 	int i;
136 
137 	if (bfa->msix.nvecs == 0)
138 		return;
139 
140 	if (bfa->msix.nvecs == 1) {
141 		for (i = BFI_MSIX_CPE_QMIN_CB; i <= BFI_MSIX_RME_QMAX_CB; i++)
142 			bfa->msix.handler[i] = bfa_msix_all;
143 		return;
144 	}
145 
146 	for (i = BFI_MSIX_CPE_QMIN_CB; i <= BFI_MSIX_CPE_QMAX_CB; i++)
147 		bfa->msix.handler[i] = bfa_msix_reqq;
148 
149 	for (i = BFI_MSIX_RME_QMIN_CB; i <= BFI_MSIX_RME_QMAX_CB; i++)
150 		bfa->msix.handler[i] = bfa_msix_rspq;
151 }
152 
153 void
bfa_hwcb_msix_uninstall(struct bfa_s * bfa)154 bfa_hwcb_msix_uninstall(struct bfa_s *bfa)
155 {
156 	int i;
157 
158 	for (i = 0; i < BFI_MSIX_CB_MAX; i++)
159 		bfa->msix.handler[i] = bfa_hwcb_msix_dummy;
160 }
161 
162 /*
163  * No special enable/disable -- vector assignments are implicit.
164  */
165 void
bfa_hwcb_isr_mode_set(struct bfa_s * bfa,bfa_boolean_t msix)166 bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix)
167 {
168 	if (msix) {
169 		bfa->iocfc.hwif.hw_reqq_ack = bfa_hwcb_reqq_ack_msix;
170 		bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix;
171 	} else {
172 		bfa->iocfc.hwif.hw_reqq_ack = NULL;
173 		bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack;
174 	}
175 }
176 
177 void
bfa_hwcb_msix_get_rme_range(struct bfa_s * bfa,u32 * start,u32 * end)178 bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end)
179 {
180 	*start = BFI_MSIX_RME_QMIN_CB;
181 	*end = BFI_MSIX_RME_QMAX_CB;
182 }
183