2 * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
6 * Linux driver for Brocade Fibre Channel Host Bus Adapter.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License (GPL) Version 2 as
10 * published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
20 BFA_TRC_FILE(HAL
, SGPG
);
24 * bfa_sgpg_mod BFA SGPG Mode module
28 * Compute and return memory needed by FCP(im) module.
31 bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s
*cfg
, u32
*km_len
,
34 if (cfg
->drvcfg
.num_sgpgs
< BFA_SGPG_MIN
)
35 cfg
->drvcfg
.num_sgpgs
= BFA_SGPG_MIN
;
37 *km_len
+= (cfg
->drvcfg
.num_sgpgs
+ 1) * sizeof(struct bfa_sgpg_s
);
38 *dm_len
+= (cfg
->drvcfg
.num_sgpgs
+ 1) * sizeof(struct bfi_sgpg_s
);
43 bfa_sgpg_attach(struct bfa_s
*bfa
, void *bfad
, struct bfa_iocfc_cfg_s
*cfg
,
44 struct bfa_meminfo_s
*minfo
, struct bfa_pcidev_s
*pcidev
)
46 struct bfa_sgpg_mod_s
*mod
= BFA_SGPG_MOD(bfa
);
48 struct bfa_sgpg_s
*hsgpg
;
49 struct bfi_sgpg_s
*sgpg
;
54 union bfi_addr_u addr
;
57 INIT_LIST_HEAD(&mod
->sgpg_q
);
58 INIT_LIST_HEAD(&mod
->sgpg_wait_q
);
60 bfa_trc(bfa
, cfg
->drvcfg
.num_sgpgs
);
62 mod
->num_sgpgs
= cfg
->drvcfg
.num_sgpgs
;
63 mod
->sgpg_arr_pa
= bfa_meminfo_dma_phys(minfo
);
64 align_len
= (BFA_SGPG_ROUNDUP(mod
->sgpg_arr_pa
) - mod
->sgpg_arr_pa
);
65 mod
->sgpg_arr_pa
+= align_len
;
66 mod
->hsgpg_arr
= (struct bfa_sgpg_s
*) (bfa_meminfo_kva(minfo
) +
68 mod
->sgpg_arr
= (struct bfi_sgpg_s
*) (bfa_meminfo_dma_virt(minfo
) +
71 hsgpg
= mod
->hsgpg_arr
;
73 sgpg_pa
.pa
= mod
->sgpg_arr_pa
;
74 mod
->free_sgpgs
= mod
->num_sgpgs
;
76 bfa_assert(!(sgpg_pa
.pa
& (sizeof(struct bfi_sgpg_s
) - 1)));
78 for (i
= 0; i
< mod
->num_sgpgs
; i
++) {
79 bfa_os_memset(hsgpg
, 0, sizeof(*hsgpg
));
80 bfa_os_memset(sgpg
, 0, sizeof(*sgpg
));
83 hsgpg
->sgpg_pa
= sgpg_pa
.addr
;
84 list_add_tail(&hsgpg
->qe
, &mod
->sgpg_q
);
88 sgpg_pa
.pa
+= sizeof(struct bfi_sgpg_s
);
91 bfa_meminfo_kva(minfo
) = (u8
*) hsgpg
;
92 bfa_meminfo_dma_virt(minfo
) = (u8
*) sgpg
;
93 bfa_meminfo_dma_phys(minfo
) = sgpg_pa
.pa
;
97 bfa_sgpg_initdone(struct bfa_s
*bfa
)
102 bfa_sgpg_detach(struct bfa_s
*bfa
)
107 bfa_sgpg_start(struct bfa_s
*bfa
)
112 bfa_sgpg_stop(struct bfa_s
*bfa
)
117 bfa_sgpg_iocdisable(struct bfa_s
*bfa
)
124 * bfa_sgpg_public BFA SGPG public functions
128 bfa_sgpg_malloc(struct bfa_s
*bfa
, struct list_head
*sgpg_q
, int nsgpgs
)
130 struct bfa_sgpg_mod_s
*mod
= BFA_SGPG_MOD(bfa
);
131 struct bfa_sgpg_s
*hsgpg
;
134 bfa_trc_fp(bfa
, nsgpgs
);
136 if (mod
->free_sgpgs
< nsgpgs
)
137 return BFA_STATUS_ENOMEM
;
139 for (i
= 0; i
< nsgpgs
; i
++) {
140 bfa_q_deq(&mod
->sgpg_q
, &hsgpg
);
142 list_add_tail(&hsgpg
->qe
, sgpg_q
);
145 mod
->free_sgpgs
-= nsgpgs
;
146 return BFA_STATUS_OK
;
150 bfa_sgpg_mfree(struct bfa_s
*bfa
, struct list_head
*sgpg_q
, int nsgpg
)
152 struct bfa_sgpg_mod_s
*mod
= BFA_SGPG_MOD(bfa
);
153 struct bfa_sgpg_wqe_s
*wqe
;
155 bfa_trc_fp(bfa
, nsgpg
);
157 mod
->free_sgpgs
+= nsgpg
;
158 bfa_assert(mod
->free_sgpgs
<= mod
->num_sgpgs
);
160 list_splice_tail_init(sgpg_q
, &mod
->sgpg_q
);
162 if (list_empty(&mod
->sgpg_wait_q
))
166 * satisfy as many waiting requests as possible
169 wqe
= bfa_q_first(&mod
->sgpg_wait_q
);
170 if (mod
->free_sgpgs
< wqe
->nsgpg
)
171 nsgpg
= mod
->free_sgpgs
;
174 bfa_sgpg_malloc(bfa
, &wqe
->sgpg_q
, nsgpg
);
176 if (wqe
->nsgpg
== 0) {
178 wqe
->cbfn(wqe
->cbarg
);
180 } while (mod
->free_sgpgs
&& !list_empty(&mod
->sgpg_wait_q
));
184 bfa_sgpg_wait(struct bfa_s
*bfa
, struct bfa_sgpg_wqe_s
*wqe
, int nsgpg
)
186 struct bfa_sgpg_mod_s
*mod
= BFA_SGPG_MOD(bfa
);
188 bfa_assert(nsgpg
> 0);
189 bfa_assert(nsgpg
> mod
->free_sgpgs
);
191 wqe
->nsgpg_total
= wqe
->nsgpg
= nsgpg
;
194 * allocate any left to this one first
196 if (mod
->free_sgpgs
) {
198 * no one else is waiting for SGPG
200 bfa_assert(list_empty(&mod
->sgpg_wait_q
));
201 list_splice_tail_init(&mod
->sgpg_q
, &wqe
->sgpg_q
);
202 wqe
->nsgpg
-= mod
->free_sgpgs
;
206 list_add_tail(&wqe
->qe
, &mod
->sgpg_wait_q
);
210 bfa_sgpg_wcancel(struct bfa_s
*bfa
, struct bfa_sgpg_wqe_s
*wqe
)
212 struct bfa_sgpg_mod_s
*mod
= BFA_SGPG_MOD(bfa
);
214 bfa_assert(bfa_q_is_on_q(&mod
->sgpg_wait_q
, wqe
));
217 if (wqe
->nsgpg_total
!= wqe
->nsgpg
)
218 bfa_sgpg_mfree(bfa
, &wqe
->sgpg_q
,
219 wqe
->nsgpg_total
- wqe
->nsgpg
);
223 bfa_sgpg_winit(struct bfa_sgpg_wqe_s
*wqe
, void (*cbfn
) (void *cbarg
),
226 INIT_LIST_HEAD(&wqe
->sgpg_q
);