 ed96932470
			
		
	
	
	ed96932470
	
	
	
		
			
			The patch includes the driver side changes to enable basic PBC (PreBoot Configuration) feature. - Data structure changes and new definitions for PBC. - APIs to access PBC info. - Remove unused code. Signed-off-by: Jing Huang <huangj@brocade.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
		
			
				
	
	
		
			226 lines
		
	
	
	
		
			4.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
	
		
			4.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
 | |
|  * All rights reserved
 | |
|  * www.brocade.com
 | |
|  *
 | |
|  * Linux driver for Brocade Fibre Channel Host Bus Adapter.
 | |
|  *
 | |
|  * This program is free software; you can redistribute it and/or modify it
 | |
|  * under the terms of the GNU General Public License (GPL) Version 2 as
 | |
|  * published by the Free Software Foundation
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful, but
 | |
|  * WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
|  * General Public License for more details.
 | |
|  */
 | |
| 
 | |
| #include <bfa.h>
 | |
| 
 | |
| BFA_TRC_FILE(HAL, SGPG);
 | |
| BFA_MODULE(sgpg);
 | |
| 
 | |
| /**
 | |
|  *  bfa_sgpg_mod BFA SGPG Mode module
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Compute and return memory needed by FCP(im) module.
 | |
|  */
 | |
| static void
 | |
| bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
 | |
| 		u32 *dm_len)
 | |
| {
 | |
| 	if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN)
 | |
| 		cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN;
 | |
| 
 | |
| 	*km_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfa_sgpg_s);
 | |
| 	*dm_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfi_sgpg_s);
 | |
| }
 | |
| 
 | |
| 
 | |
| static void
 | |
| bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
 | |
| 		    struct bfa_meminfo_s *minfo, struct bfa_pcidev_s *pcidev)
 | |
| {
 | |
| 	struct bfa_sgpg_mod_s	*mod = BFA_SGPG_MOD(bfa);
 | |
| 	int				i;
 | |
| 	struct bfa_sgpg_s		*hsgpg;
 | |
| 	struct bfi_sgpg_s 	*sgpg;
 | |
| 	u64		align_len;
 | |
| 
 | |
| 	union {
 | |
| 		u64        pa;
 | |
| 		union bfi_addr_u      addr;
 | |
| 	} sgpg_pa;
 | |
| 
 | |
| 	INIT_LIST_HEAD(&mod->sgpg_q);
 | |
| 	INIT_LIST_HEAD(&mod->sgpg_wait_q);
 | |
| 
 | |
| 	bfa_trc(bfa, cfg->drvcfg.num_sgpgs);
 | |
| 
 | |
| 	mod->num_sgpgs = cfg->drvcfg.num_sgpgs;
 | |
| 	mod->sgpg_arr_pa = bfa_meminfo_dma_phys(minfo);
 | |
| 	align_len = (BFA_SGPG_ROUNDUP(mod->sgpg_arr_pa) - mod->sgpg_arr_pa);
 | |
| 	mod->sgpg_arr_pa += align_len;
 | |
| 	mod->hsgpg_arr = (struct bfa_sgpg_s *) (bfa_meminfo_kva(minfo) +
 | |
| 						align_len);
 | |
| 	mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) +
 | |
| 						align_len);
 | |
| 
 | |
| 	hsgpg = mod->hsgpg_arr;
 | |
| 	sgpg = mod->sgpg_arr;
 | |
| 	sgpg_pa.pa = mod->sgpg_arr_pa;
 | |
| 	mod->free_sgpgs = mod->num_sgpgs;
 | |
| 
 | |
| 	bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1)));
 | |
| 
 | |
| 	for (i = 0; i < mod->num_sgpgs; i++) {
 | |
| 		bfa_os_memset(hsgpg, 0, sizeof(*hsgpg));
 | |
| 		bfa_os_memset(sgpg, 0, sizeof(*sgpg));
 | |
| 
 | |
| 		hsgpg->sgpg = sgpg;
 | |
| 		hsgpg->sgpg_pa = sgpg_pa.addr;
 | |
| 		list_add_tail(&hsgpg->qe, &mod->sgpg_q);
 | |
| 
 | |
| 		hsgpg++;
 | |
| 		sgpg++;
 | |
| 		sgpg_pa.pa += sizeof(struct bfi_sgpg_s);
 | |
| 	}
 | |
| 
 | |
| 	bfa_meminfo_kva(minfo) = (u8 *) hsgpg;
 | |
| 	bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg;
 | |
| 	bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa;
 | |
| }
 | |
| 
 | |
| static void
 | |
| bfa_sgpg_detach(struct bfa_s *bfa)
 | |
| {
 | |
| }
 | |
| 
 | |
| static void
 | |
| bfa_sgpg_start(struct bfa_s *bfa)
 | |
| {
 | |
| }
 | |
| 
 | |
| static void
 | |
| bfa_sgpg_stop(struct bfa_s *bfa)
 | |
| {
 | |
| }
 | |
| 
 | |
| static void
 | |
| bfa_sgpg_iocdisable(struct bfa_s *bfa)
 | |
| {
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|  *  bfa_sgpg_public BFA SGPG public functions
 | |
|  */
 | |
| 
 | |
| bfa_status_t
 | |
| bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs)
 | |
| {
 | |
| 	struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
 | |
| 	struct bfa_sgpg_s *hsgpg;
 | |
| 	int             i;
 | |
| 
 | |
| 	bfa_trc_fp(bfa, nsgpgs);
 | |
| 
 | |
| 	if (mod->free_sgpgs < nsgpgs)
 | |
| 		return BFA_STATUS_ENOMEM;
 | |
| 
 | |
| 	for (i = 0; i < nsgpgs; i++) {
 | |
| 		bfa_q_deq(&mod->sgpg_q, &hsgpg);
 | |
| 		bfa_assert(hsgpg);
 | |
| 		list_add_tail(&hsgpg->qe, sgpg_q);
 | |
| 	}
 | |
| 
 | |
| 	mod->free_sgpgs -= nsgpgs;
 | |
| 	return BFA_STATUS_OK;
 | |
| }
 | |
| 
 | |
| void
 | |
| bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg)
 | |
| {
 | |
| 	struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
 | |
| 	struct bfa_sgpg_wqe_s *wqe;
 | |
| 
 | |
| 	bfa_trc_fp(bfa, nsgpg);
 | |
| 
 | |
| 	mod->free_sgpgs += nsgpg;
 | |
| 	bfa_assert(mod->free_sgpgs <= mod->num_sgpgs);
 | |
| 
 | |
| 	list_splice_tail_init(sgpg_q, &mod->sgpg_q);
 | |
| 
 | |
| 	if (list_empty(&mod->sgpg_wait_q))
 | |
| 		return;
 | |
| 
 | |
| 	/**
 | |
| 	 * satisfy as many waiting requests as possible
 | |
| 	 */
 | |
| 	do {
 | |
| 		wqe = bfa_q_first(&mod->sgpg_wait_q);
 | |
| 		if (mod->free_sgpgs < wqe->nsgpg)
 | |
| 			nsgpg = mod->free_sgpgs;
 | |
| 		else
 | |
| 			nsgpg = wqe->nsgpg;
 | |
| 		bfa_sgpg_malloc(bfa, &wqe->sgpg_q, nsgpg);
 | |
| 		wqe->nsgpg -= nsgpg;
 | |
| 		if (wqe->nsgpg == 0) {
 | |
| 			list_del(&wqe->qe);
 | |
| 			wqe->cbfn(wqe->cbarg);
 | |
| 		}
 | |
| 	} while (mod->free_sgpgs && !list_empty(&mod->sgpg_wait_q));
 | |
| }
 | |
| 
 | |
| void
 | |
| bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg)
 | |
| {
 | |
| 	struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
 | |
| 
 | |
| 	bfa_assert(nsgpg > 0);
 | |
| 	bfa_assert(nsgpg > mod->free_sgpgs);
 | |
| 
 | |
| 	wqe->nsgpg_total = wqe->nsgpg = nsgpg;
 | |
| 
 | |
| 	/**
 | |
| 	 * allocate any left to this one first
 | |
| 	 */
 | |
| 	if (mod->free_sgpgs) {
 | |
| 		/**
 | |
| 		 * no one else is waiting for SGPG
 | |
| 		 */
 | |
| 		bfa_assert(list_empty(&mod->sgpg_wait_q));
 | |
| 		list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q);
 | |
| 		wqe->nsgpg -= mod->free_sgpgs;
 | |
| 		mod->free_sgpgs = 0;
 | |
| 	}
 | |
| 
 | |
| 	list_add_tail(&wqe->qe, &mod->sgpg_wait_q);
 | |
| }
 | |
| 
 | |
| void
 | |
| bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe)
 | |
| {
 | |
| 	struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
 | |
| 
 | |
| 	bfa_assert(bfa_q_is_on_q(&mod->sgpg_wait_q, wqe));
 | |
| 	list_del(&wqe->qe);
 | |
| 
 | |
| 	if (wqe->nsgpg_total != wqe->nsgpg)
 | |
| 		bfa_sgpg_mfree(bfa, &wqe->sgpg_q,
 | |
| 				   wqe->nsgpg_total - wqe->nsgpg);
 | |
| }
 | |
| 
 | |
| void
 | |
| bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg),
 | |
| 		   void *cbarg)
 | |
| {
 | |
| 	INIT_LIST_HEAD(&wqe->sgpg_q);
 | |
| 	wqe->cbfn = cbfn;
 | |
| 	wqe->cbarg = cbarg;
 | |
| }
 | |
| 
 | |
| 
 |