]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/scsi/bfa/bfa_sgpg.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph...
[mv-sheeva.git] / drivers / scsi / bfa / bfa_sgpg.c
1 /*
2  * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
3  * All rights reserved
4  * www.brocade.com
5  *
6  * Linux driver for Brocade Fibre Channel Host Bus Adapter.
7  *
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
11  *
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.
16  */
17
18 #include <bfa.h>
19
20 BFA_TRC_FILE(HAL, SGPG);
21 BFA_MODULE(sgpg);
22
23 /**
24  *  bfa_sgpg_mod BFA SGPG Mode module
25  */
26
27 /**
28  * Compute and return memory needed by FCP(im) module.
29  */
30 static void
31 bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
32                 u32 *dm_len)
33 {
34         if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN)
35                 cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN;
36
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);
39 }
40
41
42 static void
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)
45 {
46         struct bfa_sgpg_mod_s   *mod = BFA_SGPG_MOD(bfa);
47         int                             i;
48         struct bfa_sgpg_s               *hsgpg;
49         struct bfi_sgpg_s       *sgpg;
50         u64             align_len;
51
52         union {
53                 u64        pa;
54                 union bfi_addr_u      addr;
55         } sgpg_pa;
56
57         INIT_LIST_HEAD(&mod->sgpg_q);
58         INIT_LIST_HEAD(&mod->sgpg_wait_q);
59
60         bfa_trc(bfa, cfg->drvcfg.num_sgpgs);
61
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) +
67                                                 align_len);
68         mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) +
69                                                 align_len);
70
71         hsgpg = mod->hsgpg_arr;
72         sgpg = mod->sgpg_arr;
73         sgpg_pa.pa = mod->sgpg_arr_pa;
74         mod->free_sgpgs = mod->num_sgpgs;
75
76         bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1)));
77
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));
81
82                 hsgpg->sgpg = sgpg;
83                 hsgpg->sgpg_pa = sgpg_pa.addr;
84                 list_add_tail(&hsgpg->qe, &mod->sgpg_q);
85
86                 hsgpg++;
87                 sgpg++;
88                 sgpg_pa.pa += sizeof(struct bfi_sgpg_s);
89         }
90
91         bfa_meminfo_kva(minfo) = (u8 *) hsgpg;
92         bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg;
93         bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa;
94 }
95
96 static void
97 bfa_sgpg_detach(struct bfa_s *bfa)
98 {
99 }
100
101 static void
102 bfa_sgpg_start(struct bfa_s *bfa)
103 {
104 }
105
106 static void
107 bfa_sgpg_stop(struct bfa_s *bfa)
108 {
109 }
110
111 static void
112 bfa_sgpg_iocdisable(struct bfa_s *bfa)
113 {
114 }
115
116
117
118 /**
119  *  bfa_sgpg_public BFA SGPG public functions
120  */
121
122 bfa_status_t
123 bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs)
124 {
125         struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
126         struct bfa_sgpg_s *hsgpg;
127         int             i;
128
129         bfa_trc_fp(bfa, nsgpgs);
130
131         if (mod->free_sgpgs < nsgpgs)
132                 return BFA_STATUS_ENOMEM;
133
134         for (i = 0; i < nsgpgs; i++) {
135                 bfa_q_deq(&mod->sgpg_q, &hsgpg);
136                 bfa_assert(hsgpg);
137                 list_add_tail(&hsgpg->qe, sgpg_q);
138         }
139
140         mod->free_sgpgs -= nsgpgs;
141         return BFA_STATUS_OK;
142 }
143
144 void
145 bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg)
146 {
147         struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
148         struct bfa_sgpg_wqe_s *wqe;
149
150         bfa_trc_fp(bfa, nsgpg);
151
152         mod->free_sgpgs += nsgpg;
153         bfa_assert(mod->free_sgpgs <= mod->num_sgpgs);
154
155         list_splice_tail_init(sgpg_q, &mod->sgpg_q);
156
157         if (list_empty(&mod->sgpg_wait_q))
158                 return;
159
160         /**
161          * satisfy as many waiting requests as possible
162          */
163         do {
164                 wqe = bfa_q_first(&mod->sgpg_wait_q);
165                 if (mod->free_sgpgs < wqe->nsgpg)
166                         nsgpg = mod->free_sgpgs;
167                 else
168                         nsgpg = wqe->nsgpg;
169                 bfa_sgpg_malloc(bfa, &wqe->sgpg_q, nsgpg);
170                 wqe->nsgpg -= nsgpg;
171                 if (wqe->nsgpg == 0) {
172                         list_del(&wqe->qe);
173                         wqe->cbfn(wqe->cbarg);
174                 }
175         } while (mod->free_sgpgs && !list_empty(&mod->sgpg_wait_q));
176 }
177
178 void
179 bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg)
180 {
181         struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
182
183         bfa_assert(nsgpg > 0);
184         bfa_assert(nsgpg > mod->free_sgpgs);
185
186         wqe->nsgpg_total = wqe->nsgpg = nsgpg;
187
188         /**
189          * allocate any left to this one first
190          */
191         if (mod->free_sgpgs) {
192                 /**
193                  * no one else is waiting for SGPG
194                  */
195                 bfa_assert(list_empty(&mod->sgpg_wait_q));
196                 list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q);
197                 wqe->nsgpg -= mod->free_sgpgs;
198                 mod->free_sgpgs = 0;
199         }
200
201         list_add_tail(&wqe->qe, &mod->sgpg_wait_q);
202 }
203
204 void
205 bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe)
206 {
207         struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
208
209         bfa_assert(bfa_q_is_on_q(&mod->sgpg_wait_q, wqe));
210         list_del(&wqe->qe);
211
212         if (wqe->nsgpg_total != wqe->nsgpg)
213                 bfa_sgpg_mfree(bfa, &wqe->sgpg_q,
214                                    wqe->nsgpg_total - wqe->nsgpg);
215 }
216
217 void
218 bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg),
219                    void *cbarg)
220 {
221         INIT_LIST_HEAD(&wqe->sgpg_q);
222         wqe->cbfn = cbfn;
223         wqe->cbarg = cbarg;
224 }
225
226