1*d14abf15SRobert Mustacchi 
2*d14abf15SRobert Mustacchi /*******************************************************************************
3*d14abf15SRobert Mustacchi * bd_chain.h - bd chain interface
4*d14abf15SRobert Mustacchi *******************************************************************************/
5*d14abf15SRobert Mustacchi #ifndef _BD_CHAIN_H
6*d14abf15SRobert Mustacchi #define _BD_CHAIN_H
7*d14abf15SRobert Mustacchi 
8*d14abf15SRobert Mustacchi /* The number of bd's per page including the last bd which is used as
9*d14abf15SRobert Mustacchi  * a pointer to the next bd page. */
10*d14abf15SRobert Mustacchi #define BD_PER_PAGE(bd_size)        (LM_PAGE_SIZE/(bd_size))
11*d14abf15SRobert Mustacchi 
12*d14abf15SRobert Mustacchi /* Number of bds that are used for the 'next' prt. The next ptr is constant size (sizeof lm_bd_chain_next). however,
13*d14abf15SRobert Mustacchi  * we will always work with 'full' bds. So if the bd-size is smaller than the next-ptr, we will use several, if it is
14*d14abf15SRobert Mustacchi  * larger, we will use a full one (no partial bds...) The equation 1+((next_bd_size-1)/bd_size) gives us the number of bds
15*d14abf15SRobert Mustacchi  * we need for this purpose. */
16*d14abf15SRobert Mustacchi #define NUM_BDS_USED_FOR_NEXT_PTR(bd_size,is_chain_mode) ((is_chain_mode)? (1 + ((sizeof(lm_bd_chain_next)-1) / (bd_size))): 0)
17*d14abf15SRobert Mustacchi 
18*d14abf15SRobert Mustacchi /* The number of useable bd's per page.  This number does not include the bds at the end of the page used for the 'next-bd' */
19*d14abf15SRobert Mustacchi #define USABLE_BDS_PER_PAGE(bd_size,is_chain_mode)    ((u32_t) (BD_PER_PAGE(bd_size)-NUM_BDS_USED_FOR_NEXT_PTR(bd_size,is_chain_mode)))
20*d14abf15SRobert Mustacchi 
21*d14abf15SRobert Mustacchi 
22*d14abf15SRobert Mustacchi /* return number of available bds, i.e. _usable_ not produced bds */
lm_bd_chain_avail_bds(lm_bd_chain_t * bd_chain)23*d14abf15SRobert Mustacchi __inline static u16_t lm_bd_chain_avail_bds(lm_bd_chain_t* bd_chain)
24*d14abf15SRobert Mustacchi {
25*d14abf15SRobert Mustacchi     return bd_chain->bd_left;
26*d14abf15SRobert Mustacchi }
27*d14abf15SRobert Mustacchi 
28*d14abf15SRobert Mustacchi /* return the cyclic prod idx */
lm_bd_chain_prod_idx(lm_bd_chain_t * bd_chain)29*d14abf15SRobert Mustacchi __inline static u16_t lm_bd_chain_prod_idx(lm_bd_chain_t* bd_chain)
30*d14abf15SRobert Mustacchi {
31*d14abf15SRobert Mustacchi     return bd_chain->prod_idx;
32*d14abf15SRobert Mustacchi }
33*d14abf15SRobert Mustacchi 
34*d14abf15SRobert Mustacchi /* return the cyclic cons idx */
lm_bd_chain_cons_idx(lm_bd_chain_t * bd_chain)35*d14abf15SRobert Mustacchi __inline static u16_t lm_bd_chain_cons_idx(lm_bd_chain_t* bd_chain)
36*d14abf15SRobert Mustacchi {
37*d14abf15SRobert Mustacchi     return bd_chain->cons_idx;
38*d14abf15SRobert Mustacchi }
39*d14abf15SRobert Mustacchi 
40*d14abf15SRobert Mustacchi /* return the usable_bds_per_page */
lm_bd_chain_usable_bds_per_page(lm_bd_chain_t * bd_chain)41*d14abf15SRobert Mustacchi __inline static u16_t lm_bd_chain_usable_bds_per_page(lm_bd_chain_t* bd_chain)
42*d14abf15SRobert Mustacchi {
43*d14abf15SRobert Mustacchi     return bd_chain->usable_bds_per_page;
44*d14abf15SRobert Mustacchi }
45*d14abf15SRobert Mustacchi 
46*d14abf15SRobert Mustacchi /* return the page_cnt */
lm_bd_chain_page_cnt(lm_bd_chain_t * bd_chain)47*d14abf15SRobert Mustacchi __inline static u16_t lm_bd_chain_page_cnt(lm_bd_chain_t* bd_chain)
48*d14abf15SRobert Mustacchi {
49*d14abf15SRobert Mustacchi     return bd_chain->page_cnt;
50*d14abf15SRobert Mustacchi }
51*d14abf15SRobert Mustacchi 
52*d14abf15SRobert Mustacchi /* return the bds_per_page */
lm_bd_chain_bds_per_page(lm_bd_chain_t * bd_chain)53*d14abf15SRobert Mustacchi __inline static u16_t lm_bd_chain_bds_per_page(lm_bd_chain_t* bd_chain)
54*d14abf15SRobert Mustacchi {
55*d14abf15SRobert Mustacchi     return bd_chain->bds_per_page;
56*d14abf15SRobert Mustacchi }
57*d14abf15SRobert Mustacchi 
58*d14abf15SRobert Mustacchi /* return the bds_per_page_mask */
lm_bd_chain_bds_per_page_mask(lm_bd_chain_t * bd_chain)59*d14abf15SRobert Mustacchi __inline static u16_t lm_bd_chain_bds_per_page_mask(lm_bd_chain_t* bd_chain)
60*d14abf15SRobert Mustacchi {
61*d14abf15SRobert Mustacchi     return bd_chain->bds_per_page_mask;
62*d14abf15SRobert Mustacchi }
63*d14abf15SRobert Mustacchi 
64*d14abf15SRobert Mustacchi /* return the bds_skip_eop */
lm_bd_chain_bds_skip_eop(lm_bd_chain_t * bd_chain)65*d14abf15SRobert Mustacchi __inline static u16_t lm_bd_chain_bds_skip_eop(lm_bd_chain_t* bd_chain)
66*d14abf15SRobert Mustacchi {
67*d14abf15SRobert Mustacchi     return bd_chain->bds_skip_eop;
68*d14abf15SRobert Mustacchi }
69*d14abf15SRobert Mustacchi 
70*d14abf15SRobert Mustacchi /* return empty state */
lm_bd_chain_is_empty(lm_bd_chain_t * bd_chain)71*d14abf15SRobert Mustacchi __inline static u8_t lm_bd_chain_is_empty(lm_bd_chain_t* bd_chain)
72*d14abf15SRobert Mustacchi {
73*d14abf15SRobert Mustacchi     return (bd_chain->bd_left == 0);
74*d14abf15SRobert Mustacchi }
75*d14abf15SRobert Mustacchi 
76*d14abf15SRobert Mustacchi /* return full state */
lm_bd_chain_is_full(lm_bd_chain_t * bd_chain)77*d14abf15SRobert Mustacchi __inline static u8_t lm_bd_chain_is_full(lm_bd_chain_t* bd_chain)
78*d14abf15SRobert Mustacchi {
79*d14abf15SRobert Mustacchi     return (bd_chain->bd_left == bd_chain->capacity);
80*d14abf15SRobert Mustacchi }
81*d14abf15SRobert Mustacchi 
82*d14abf15SRobert Mustacchi /* returns the phys addr of the page of given page_idx. (page_idx >= 0) */
lm_bd_chain_phys_addr(lm_bd_chain_t * bd_chain,u8_t page_idx)83*d14abf15SRobert Mustacchi __inline static lm_address_t lm_bd_chain_phys_addr(lm_bd_chain_t* bd_chain, u8_t page_idx)
84*d14abf15SRobert Mustacchi {
85*d14abf15SRobert Mustacchi     lm_address_t mem_phys = bd_chain->bd_chain_phy;
86*d14abf15SRobert Mustacchi     u8_t idx;
87*d14abf15SRobert Mustacchi 
88*d14abf15SRobert Mustacchi     page_idx = page_idx % bd_chain->page_cnt;
89*d14abf15SRobert Mustacchi 
90*d14abf15SRobert Mustacchi     if (bd_chain->b_is_chain_mode)
91*d14abf15SRobert Mustacchi     {
92*d14abf15SRobert Mustacchi         /* TODO: assumption that memory is contiguous.. */
93*d14abf15SRobert Mustacchi         for(idx = 0; idx < page_idx; idx++)
94*d14abf15SRobert Mustacchi         {
95*d14abf15SRobert Mustacchi             /* Increment mem_phy to the next page. */
96*d14abf15SRobert Mustacchi             LM_INC64(&mem_phys, LM_PAGE_SIZE);
97*d14abf15SRobert Mustacchi         }
98*d14abf15SRobert Mustacchi     }
99*d14abf15SRobert Mustacchi     else
100*d14abf15SRobert Mustacchi     {
101*d14abf15SRobert Mustacchi         mem_phys = bd_chain->pbl_phys_addr_table[page_idx];
102*d14abf15SRobert Mustacchi     }
103*d14abf15SRobert Mustacchi     return mem_phys;
104*d14abf15SRobert Mustacchi }
105*d14abf15SRobert Mustacchi 
106*d14abf15SRobert Mustacchi 
107*d14abf15SRobert Mustacchi /*******************************************************************************
108*d14abf15SRobert Mustacchi  * Description:
109*d14abf15SRobert Mustacchi  * afrer allocating the ring, this func fixes the last BD pointers at the
110*d14abf15SRobert Mustacchi  * end of a page to point to the first BD in the next page.
111*d14abf15SRobert Mustacchi  * Return:
112*d14abf15SRobert Mustacchi  ******************************************************************************/
lm_bd_chain_set_next_ptrs(lm_bd_chain_t * bd_chain)113*d14abf15SRobert Mustacchi __inline static void lm_bd_chain_set_next_ptrs(lm_bd_chain_t * bd_chain)
114*d14abf15SRobert Mustacchi {
115*d14abf15SRobert Mustacchi     lm_address_t start_mem_phy;
116*d14abf15SRobert Mustacchi     lm_address_t mem_phy;
117*d14abf15SRobert Mustacchi     lm_bd_chain_next * next_bd;
118*d14abf15SRobert Mustacchi     u8_t *start_mem_virt;
119*d14abf15SRobert Mustacchi     u8_t *mem_virt;
120*d14abf15SRobert Mustacchi     u16_t idx;
121*d14abf15SRobert Mustacchi 
122*d14abf15SRobert Mustacchi     mem_virt = bd_chain->bd_chain_virt;
123*d14abf15SRobert Mustacchi     mem_phy = bd_chain->bd_chain_phy;
124*d14abf15SRobert Mustacchi 
125*d14abf15SRobert Mustacchi     DbgBreakIf(
126*d14abf15SRobert Mustacchi         ((u32_t) PTR_SUB(mem_virt, 0) & LM_PAGE_MASK) !=
127*d14abf15SRobert Mustacchi             (mem_phy.as_u32.low & LM_PAGE_MASK));
128*d14abf15SRobert Mustacchi 
129*d14abf15SRobert Mustacchi     DbgBreakIf(!bd_chain->b_is_chain_mode);
130*d14abf15SRobert Mustacchi 
131*d14abf15SRobert Mustacchi     /* make sure all known bds structure equals to lm_bd_chain_next structure before  */
132*d14abf15SRobert Mustacchi     /* tx bd */
133*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct eth_tx_next_bd, addr_hi) == OFFSETOF(lm_bd_chain_next, addr_hi)) ;
134*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct eth_tx_next_bd, addr_lo) == OFFSETOF(lm_bd_chain_next, addr_lo)) ;
135*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct eth_tx_next_bd, reserved)== OFFSETOF(lm_bd_chain_next, reserved) ) ;
136*d14abf15SRobert Mustacchi 
137*d14abf15SRobert Mustacchi     /* rx bd */
138*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct eth_rx_bd_next_page, addr_hi) == OFFSETOF(lm_bd_chain_next, addr_hi)) ;
139*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct eth_rx_bd_next_page, addr_lo) == OFFSETOF(lm_bd_chain_next, addr_lo)) ;
140*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct eth_rx_bd_next_page, reserved)== OFFSETOF(lm_bd_chain_next, reserved) ) ;
141*d14abf15SRobert Mustacchi 
142*d14abf15SRobert Mustacchi     /* rcq */
143*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct eth_rx_cqe_next_page, addr_hi) == OFFSETOF(lm_bd_chain_next, addr_hi)) ;
144*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct eth_rx_cqe_next_page, addr_lo) == OFFSETOF(lm_bd_chain_next, addr_lo)) ;
145*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct eth_rx_cqe_next_page, reserved)== OFFSETOF(lm_bd_chain_next, reserved) ) ;
146*d14abf15SRobert Mustacchi 
147*d14abf15SRobert Mustacchi     /* Toe stuff */
148*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct toe_page_addr_bd, addr_hi) == OFFSETOF(lm_bd_chain_next, addr_hi)) ;
149*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct toe_page_addr_bd, addr_lo) == OFFSETOF(lm_bd_chain_next, addr_lo)) ;
150*d14abf15SRobert Mustacchi     ASSERT_STATIC(OFFSETOF(struct toe_page_addr_bd, reserved)== OFFSETOF(lm_bd_chain_next, reserved) ) ;
151*d14abf15SRobert Mustacchi 
152*d14abf15SRobert Mustacchi     start_mem_phy = mem_phy;
153*d14abf15SRobert Mustacchi     start_mem_virt = mem_virt;
154*d14abf15SRobert Mustacchi 
155*d14abf15SRobert Mustacchi     for(idx = 0; idx < bd_chain->page_cnt-1; idx++)
156*d14abf15SRobert Mustacchi     {
157*d14abf15SRobert Mustacchi         if CHK_NULL(mem_virt)
158*d14abf15SRobert Mustacchi         {
159*d14abf15SRobert Mustacchi             DbgBreakIfAll(!mem_virt) ;
160*d14abf15SRobert Mustacchi             return ;
161*d14abf15SRobert Mustacchi         }
162*d14abf15SRobert Mustacchi 
163*d14abf15SRobert Mustacchi         /* Increment mem_phy to the next page. */
164*d14abf15SRobert Mustacchi         LM_INC64(&mem_phy, LM_PAGE_SIZE);
165*d14abf15SRobert Mustacchi 
166*d14abf15SRobert Mustacchi         /* Initialize the physical address of the next bd chain. */
167*d14abf15SRobert Mustacchi         next_bd = (lm_bd_chain_next *)(mem_virt + (bd_chain->bd_size) * (bd_chain->usable_bds_per_page));
168*d14abf15SRobert Mustacchi 
169*d14abf15SRobert Mustacchi         next_bd->addr_hi = mm_cpu_to_le32(mem_phy.as_u32.high);
170*d14abf15SRobert Mustacchi         next_bd->addr_lo = mm_cpu_to_le32(mem_phy.as_u32.low);
171*d14abf15SRobert Mustacchi 
172*d14abf15SRobert Mustacchi         /* Initialize the virtual address of the next bd chain. */
173*d14abf15SRobert Mustacchi         *((u8_t **) next_bd->reserved) =  mem_virt + LM_PAGE_SIZE;
174*d14abf15SRobert Mustacchi 
175*d14abf15SRobert Mustacchi         /* Move to the next bd chain. */
176*d14abf15SRobert Mustacchi         mem_virt += LM_PAGE_SIZE;
177*d14abf15SRobert Mustacchi     }
178*d14abf15SRobert Mustacchi 
179*d14abf15SRobert Mustacchi     next_bd = (lm_bd_chain_next *)(mem_virt + (bd_chain->bd_size) * (bd_chain->usable_bds_per_page));
180*d14abf15SRobert Mustacchi     next_bd->addr_hi = mm_cpu_to_le32(start_mem_phy.as_u32.high);
181*d14abf15SRobert Mustacchi     next_bd->addr_lo = mm_cpu_to_le32(start_mem_phy.as_u32.low);
182*d14abf15SRobert Mustacchi     *((u8_t **) next_bd->reserved) = start_mem_virt;
183*d14abf15SRobert Mustacchi } /* lm_bd_chain_set_next_ptrs */
184*d14abf15SRobert Mustacchi 
185*d14abf15SRobert Mustacchi /* setup bd chain.
186*d14abf15SRobert Mustacchi  * - currently only physically contiguous chain format is supported
187*d14abf15SRobert Mustacchi  * -  */
188*d14abf15SRobert Mustacchi 
189*d14abf15SRobert Mustacchi unsigned long log2_align(unsigned long n);
190*d14abf15SRobert Mustacchi 
lm_bd_chain_add_page(struct _lm_device_t * pdev,lm_bd_chain_t * bd_chain,void * mem_virt,lm_address_t mem_phys,u8_t bd_size,u8_t is_chain_mode)191*d14abf15SRobert Mustacchi __inline static lm_status_t lm_bd_chain_add_page(
192*d14abf15SRobert Mustacchi     struct _lm_device_t *pdev,
193*d14abf15SRobert Mustacchi     lm_bd_chain_t*       bd_chain,
194*d14abf15SRobert Mustacchi     void                *mem_virt,  /* ptr to caller pre-allocated buffer */
195*d14abf15SRobert Mustacchi     lm_address_t         mem_phys,   /* phys addr of buffer */
196*d14abf15SRobert Mustacchi     u8_t                 bd_size,    /* currently only 8 and 16 bytes are possible */
197*d14abf15SRobert Mustacchi     u8_t                 is_chain_mode) /* Is the next pointer the last entry*/
198*d14abf15SRobert Mustacchi {
199*d14abf15SRobert Mustacchi 
200*d14abf15SRobert Mustacchi     lm_bd_chain_next * next_bd;
201*d14abf15SRobert Mustacchi 
202*d14abf15SRobert Mustacchi     UNREFERENCED_PARAMETER_(pdev);
203*d14abf15SRobert Mustacchi 
204*d14abf15SRobert Mustacchi     DbgBreakIf((bd_chain->page_cnt + 1) * BD_PER_PAGE(bd_size) > 0xffff);
205*d14abf15SRobert Mustacchi     if (is_chain_mode)
206*d14abf15SRobert Mustacchi     {
207*d14abf15SRobert Mustacchi         if (bd_chain->page_cnt) {
208*d14abf15SRobert Mustacchi             u16_t page_index;
209*d14abf15SRobert Mustacchi             DbgBreakIf(bd_chain->bd_size != bd_size);
210*d14abf15SRobert Mustacchi             next_bd = (lm_bd_chain_next *)((u8_t*)bd_chain->bd_chain_virt + (bd_chain->bd_size) * (bd_chain->usable_bds_per_page));
211*d14abf15SRobert Mustacchi             for (page_index = 0; page_index < bd_chain->page_cnt - 1; page_index++) {
212*d14abf15SRobert Mustacchi                 next_bd = (lm_bd_chain_next *)((u8_t*)(*(void **)(next_bd->reserved)) + (bd_chain->bd_size) * (bd_chain->usable_bds_per_page));
213*d14abf15SRobert Mustacchi             }
214*d14abf15SRobert Mustacchi             next_bd->addr_hi = mm_cpu_to_le32(mem_phys.as_u32.high);
215*d14abf15SRobert Mustacchi             next_bd->addr_lo = mm_cpu_to_le32(mem_phys.as_u32.low);
216*d14abf15SRobert Mustacchi             *((u8_t **) next_bd->reserved) =  mem_virt;
217*d14abf15SRobert Mustacchi             next_bd = (lm_bd_chain_next *)((u8_t*)mem_virt + (bd_chain->bd_size) * (bd_chain->usable_bds_per_page));
218*d14abf15SRobert Mustacchi             next_bd->addr_hi = mm_cpu_to_le32(bd_chain->bd_chain_phy.as_u32.high);
219*d14abf15SRobert Mustacchi             next_bd->addr_lo = mm_cpu_to_le32(bd_chain->bd_chain_phy.as_u32.low);
220*d14abf15SRobert Mustacchi             *((u8_t **) next_bd->reserved) =  bd_chain->bd_chain_virt;
221*d14abf15SRobert Mustacchi         } else {
222*d14abf15SRobert Mustacchi             bd_chain->bd_chain_phy = mem_phys;
223*d14abf15SRobert Mustacchi             bd_chain->bd_chain_virt = mem_virt;
224*d14abf15SRobert Mustacchi             bd_chain->bd_size = bd_size;
225*d14abf15SRobert Mustacchi             bd_chain->bds_skip_eop = NUM_BDS_USED_FOR_NEXT_PTR(bd_size,is_chain_mode);
226*d14abf15SRobert Mustacchi             bd_chain->usable_bds_per_page = USABLE_BDS_PER_PAGE(bd_size,is_chain_mode);
227*d14abf15SRobert Mustacchi             bd_chain->bds_per_page = BD_PER_PAGE(bd_size);
228*d14abf15SRobert Mustacchi             bd_chain->b_is_chain_mode = TRUE;
229*d14abf15SRobert Mustacchi             bd_chain->num_bd_to_sub   = 0;
230*d14abf15SRobert Mustacchi             bd_chain->usable_bds_mask = bd_chain->usable_bds_per_page;
231*d14abf15SRobert Mustacchi 
232*d14abf15SRobert Mustacchi             /* we assume power of 2 for bd_chain->bds_per_page */
233*d14abf15SRobert Mustacchi             DbgBreakIf(bd_chain->bds_per_page != log2_align((u32_t)bd_chain->bds_per_page));
234*d14abf15SRobert Mustacchi             bd_chain->bds_per_page_mask = bd_chain->bds_per_page - 1;
235*d14abf15SRobert Mustacchi             bd_chain->cons_idx = 0;
236*d14abf15SRobert Mustacchi             bd_chain->prod_idx = 0;
237*d14abf15SRobert Mustacchi             bd_chain->next_bd = bd_chain->bd_chain_virt;
238*d14abf15SRobert Mustacchi             /* Initialize the physical address of the next bd chain. */
239*d14abf15SRobert Mustacchi             next_bd = (lm_bd_chain_next *)((u8_t*)mem_virt + (bd_chain->bd_size) * (bd_chain->usable_bds_per_page));
240*d14abf15SRobert Mustacchi 
241*d14abf15SRobert Mustacchi             next_bd->addr_hi = mm_cpu_to_le32(mem_phys.as_u32.high);
242*d14abf15SRobert Mustacchi             next_bd->addr_lo = mm_cpu_to_le32(mem_phys.as_u32.low);
243*d14abf15SRobert Mustacchi 
244*d14abf15SRobert Mustacchi             /* Initialize the virtual address of the next bd chain. */
245*d14abf15SRobert Mustacchi             *((u8_t **) next_bd->reserved) =  mem_virt;
246*d14abf15SRobert Mustacchi         }
247*d14abf15SRobert Mustacchi     }
248*d14abf15SRobert Mustacchi     else
249*d14abf15SRobert Mustacchi     {
250*d14abf15SRobert Mustacchi         //TODO: currently TOE only, implement for PBL
251*d14abf15SRobert Mustacchi         //      add the physical address of the page to the next pbl_page_idx
252*d14abf15SRobert Mustacchi         //      ensure that the pbl_virt in this case is valid..
253*d14abf15SRobert Mustacchi         DbgBreak();
254*d14abf15SRobert Mustacchi     }
255*d14abf15SRobert Mustacchi 
256*d14abf15SRobert Mustacchi     bd_chain->page_cnt++;
257*d14abf15SRobert Mustacchi     bd_chain->capacity = bd_chain->page_cnt * bd_chain->usable_bds_per_page;
258*d14abf15SRobert Mustacchi     bd_chain->bd_left = bd_chain->capacity;
259*d14abf15SRobert Mustacchi 
260*d14abf15SRobert Mustacchi     return LM_STATUS_SUCCESS;
261*d14abf15SRobert Mustacchi }
262*d14abf15SRobert Mustacchi 
lm_bd_chain_setup(struct _lm_device_t * pdev,lm_bd_chain_t * bd_chain,void * mem_virt,lm_address_t mem_phys,u16_t page_cnt,u8_t bd_size,u8_t is_full,u8_t is_chain_mode)263*d14abf15SRobert Mustacchi __inline static lm_status_t lm_bd_chain_setup(
264*d14abf15SRobert Mustacchi     struct _lm_device_t *pdev,
265*d14abf15SRobert Mustacchi     lm_bd_chain_t*       bd_chain,
266*d14abf15SRobert Mustacchi     void                *mem_virt,  /* ptr to caller pre-allocated buffer */
267*d14abf15SRobert Mustacchi     lm_address_t         mem_phys,   /* phys addr of buffer */
268*d14abf15SRobert Mustacchi     u16_t                page_cnt,   /* #pages in given buffer */
269*d14abf15SRobert Mustacchi     u8_t                 bd_size,    /* currently only 8 and 16 bytes are possible */
270*d14abf15SRobert Mustacchi     u8_t                 is_full,   /* chain initial state (full or empty) */
271*d14abf15SRobert Mustacchi     u8_t                 is_chain_mode) /* Is the next pointer the last entry*/
272*d14abf15SRobert Mustacchi {
273*d14abf15SRobert Mustacchi     DbgBreakIf(page_cnt * BD_PER_PAGE(bd_size) > 0xffff);
274*d14abf15SRobert Mustacchi 
275*d14abf15SRobert Mustacchi     UNREFERENCED_PARAMETER_(pdev);
276*d14abf15SRobert Mustacchi 
277*d14abf15SRobert Mustacchi     bd_chain->bd_chain_phy = mem_phys;
278*d14abf15SRobert Mustacchi     bd_chain->bd_chain_virt = mem_virt;
279*d14abf15SRobert Mustacchi     bd_chain->bd_size = bd_size;
280*d14abf15SRobert Mustacchi     bd_chain->bds_skip_eop = NUM_BDS_USED_FOR_NEXT_PTR(bd_size,is_chain_mode);
281*d14abf15SRobert Mustacchi     bd_chain->usable_bds_per_page = USABLE_BDS_PER_PAGE(bd_size,is_chain_mode);
282*d14abf15SRobert Mustacchi     bd_chain->bds_per_page = BD_PER_PAGE(bd_size);
283*d14abf15SRobert Mustacchi 
284*d14abf15SRobert Mustacchi     /* we assume power of 2 for bd_chain->bds_per_page */
285*d14abf15SRobert Mustacchi     DbgBreakIf(bd_chain->bds_per_page != log2_align((u32_t)bd_chain->bds_per_page));
286*d14abf15SRobert Mustacchi     bd_chain->bds_per_page_mask = bd_chain->bds_per_page - 1;
287*d14abf15SRobert Mustacchi 
288*d14abf15SRobert Mustacchi #ifdef __SunOS
289*d14abf15SRobert Mustacchi     /*
290*d14abf15SRobert Mustacchi      * This minor code change fixes a compiler error in SunStudio 12u1.  The
291*d14abf15SRobert Mustacchi      * bug is that an "imulw $-0x80,..." is generated which wrecks the capacity
292*d14abf15SRobert Mustacchi      * value specifically when initializing the FCoE EQ chain.  Shifting code
293*d14abf15SRobert Mustacchi      * around and/or removing the deep inline access to this function will fix
294*d14abf15SRobert Mustacchi      * the issue but would be a kludge.  Note that I've created this ifdef to
295*d14abf15SRobert Mustacchi      * ensure someone doesn't come in later and merge these two lines together
296*d14abf15SRobert Mustacchi      * thereby reverting it to what it was before.
297*d14abf15SRobert Mustacchi      */
298*d14abf15SRobert Mustacchi     bd_chain->capacity = page_cnt;
299*d14abf15SRobert Mustacchi     bd_chain->capacity *= bd_chain->usable_bds_per_page;
300*d14abf15SRobert Mustacchi #else
301*d14abf15SRobert Mustacchi     bd_chain->capacity = page_cnt * bd_chain->usable_bds_per_page;
302*d14abf15SRobert Mustacchi #endif
303*d14abf15SRobert Mustacchi     bd_chain->page_cnt = page_cnt;
304*d14abf15SRobert Mustacchi     bd_chain->next_bd = bd_chain->bd_chain_virt;
305*d14abf15SRobert Mustacchi     bd_chain->cons_idx = 0;
306*d14abf15SRobert Mustacchi 
307*d14abf15SRobert Mustacchi     if(is_full) {
308*d14abf15SRobert Mustacchi         bd_chain->prod_idx = page_cnt * bd_chain->bds_per_page;
309*d14abf15SRobert Mustacchi         bd_chain->bd_left = 0;
310*d14abf15SRobert Mustacchi     } else {
311*d14abf15SRobert Mustacchi         bd_chain->prod_idx = 0;
312*d14abf15SRobert Mustacchi         /* Don't count the last bd of a BD page.  A full BD chain must
313*d14abf15SRobert Mustacchi          * have at least one empty entry.  */
314*d14abf15SRobert Mustacchi         bd_chain->bd_left = bd_chain->capacity;
315*d14abf15SRobert Mustacchi     }
316*d14abf15SRobert Mustacchi     if(is_chain_mode)
317*d14abf15SRobert Mustacchi     {
318*d14abf15SRobert Mustacchi         bd_chain->b_is_chain_mode = TRUE;
319*d14abf15SRobert Mustacchi         bd_chain->num_bd_to_sub   = 0;
320*d14abf15SRobert Mustacchi         bd_chain->usable_bds_mask = bd_chain->usable_bds_per_page;
321*d14abf15SRobert Mustacchi         lm_bd_chain_set_next_ptrs(bd_chain);
322*d14abf15SRobert Mustacchi     }
323*d14abf15SRobert Mustacchi 
324*d14abf15SRobert Mustacchi     return LM_STATUS_SUCCESS;
325*d14abf15SRobert Mustacchi }
326*d14abf15SRobert Mustacchi 
lm_bd_chain_pbl_set_ptrs(IN void * buf_base_virt,IN lm_address_t buf_base_phy,IN lm_address_t * pbl_phys_table,IN void * pbl_virt_table,IN u32_t pbl_entries)327*d14abf15SRobert Mustacchi __inline static lm_status_t lm_bd_chain_pbl_set_ptrs(
328*d14abf15SRobert Mustacchi     IN  void         *buf_base_virt,    /* ptr to caller pre-allocated buffer */
329*d14abf15SRobert Mustacchi     IN  lm_address_t buf_base_phy,      /* phys addr of the pre-allocated buffer */
330*d14abf15SRobert Mustacchi     IN  lm_address_t *pbl_phys_table,   /* ptr to caller pre-allocated buffer of phys pbl */
331*d14abf15SRobert Mustacchi     IN  void         *pbl_virt_table,   /* ptr to caller pre-allocated buffer of virt pbl */
332*d14abf15SRobert Mustacchi     IN  u32_t         pbl_entries       /* #pages in given buffer */
333*d14abf15SRobert Mustacchi     )
334*d14abf15SRobert Mustacchi {
335*d14abf15SRobert Mustacchi 	u32_t i;
336*d14abf15SRobert Mustacchi 
337*d14abf15SRobert Mustacchi 	if (CHK_NULL(buf_base_virt) ||
338*d14abf15SRobert Mustacchi         CHK_NULL(pbl_phys_table) ||
339*d14abf15SRobert Mustacchi         CHK_NULL(pbl_virt_table) ||
340*d14abf15SRobert Mustacchi         (pbl_entries == 0))
341*d14abf15SRobert Mustacchi 	{
342*d14abf15SRobert Mustacchi         return LM_STATUS_INVALID_PARAMETER;
343*d14abf15SRobert Mustacchi     }
344*d14abf15SRobert Mustacchi 
345*d14abf15SRobert Mustacchi 	/* fill page table elements */
346*d14abf15SRobert Mustacchi 	for (i = 0; i < pbl_entries; i++)
347*d14abf15SRobert Mustacchi     {
348*d14abf15SRobert Mustacchi #ifdef BIG_ENDIAN
349*d14abf15SRobert Mustacchi         pbl_phys_table[i].as_u32.low = mm_cpu_to_le32(buf_base_phy.as_u32.high);
350*d14abf15SRobert Mustacchi         pbl_phys_table[i].as_u32.high = mm_cpu_to_le32(buf_base_phy.as_u32.low);
351*d14abf15SRobert Mustacchi #else // LITTLE_ENDIAN
352*d14abf15SRobert Mustacchi         pbl_phys_table[i].as_u64 = buf_base_phy.as_u64;
353*d14abf15SRobert Mustacchi #endif
354*d14abf15SRobert Mustacchi 
355*d14abf15SRobert Mustacchi         *(void **)(((u8_t *)pbl_virt_table + (sizeof(void *) * i))) = buf_base_virt;
356*d14abf15SRobert Mustacchi 
357*d14abf15SRobert Mustacchi         /* Increment mem_phy to the next page. */
358*d14abf15SRobert Mustacchi         /* TODO: assumption that memory is contiguous.. */
359*d14abf15SRobert Mustacchi         LM_INC64(&buf_base_phy, LM_PAGE_SIZE);
360*d14abf15SRobert Mustacchi 
361*d14abf15SRobert Mustacchi         buf_base_virt = (u8_t *)buf_base_virt + LM_PAGE_SIZE;
362*d14abf15SRobert Mustacchi      }
363*d14abf15SRobert Mustacchi 
364*d14abf15SRobert Mustacchi 	return LM_STATUS_SUCCESS;
365*d14abf15SRobert Mustacchi }
366*d14abf15SRobert Mustacchi 
367*d14abf15SRobert Mustacchi 
lm_bd_chain_pbl_setup(struct _lm_device_t * pdev,lm_bd_chain_t * bd_chain,void * mem_virt,lm_address_t mem_phys,void * pbl_virt_table,lm_address_t * pbl_phys_table,u16_t page_cnt,u8_t bd_size,u8_t is_full)368*d14abf15SRobert Mustacchi __inline static lm_status_t lm_bd_chain_pbl_setup(
369*d14abf15SRobert Mustacchi     struct _lm_device_t *pdev,
370*d14abf15SRobert Mustacchi     lm_bd_chain_t*       bd_chain,
371*d14abf15SRobert Mustacchi     void                *mem_virt,           /* ptr to caller pre-allocated buffer */
372*d14abf15SRobert Mustacchi     lm_address_t         mem_phys,           /* phys addr of buffer */
373*d14abf15SRobert Mustacchi     void                *pbl_virt_table,     /* ptr to caller pre-allocated buffer of virt pbl */
374*d14abf15SRobert Mustacchi     lm_address_t        *pbl_phys_table,     /* ptr to caller pre-allocated buffer of phys pbl */
375*d14abf15SRobert Mustacchi     u16_t                page_cnt,           /* #pages in given buffer */
376*d14abf15SRobert Mustacchi     u8_t                 bd_size,            /* currently only 8 and 16 bytes are possible */
377*d14abf15SRobert Mustacchi     u8_t                 is_full)            /* chain initial state (full or empty) */
378*d14abf15SRobert Mustacchi {
379*d14abf15SRobert Mustacchi     lm_status_t lm_status;
380*d14abf15SRobert Mustacchi 
381*d14abf15SRobert Mustacchi     lm_status = lm_bd_chain_setup(pdev,
382*d14abf15SRobert Mustacchi                                   bd_chain,
383*d14abf15SRobert Mustacchi                                   mem_virt,
384*d14abf15SRobert Mustacchi                                   mem_phys,
385*d14abf15SRobert Mustacchi                                   page_cnt,
386*d14abf15SRobert Mustacchi                                   bd_size,
387*d14abf15SRobert Mustacchi                                   is_full,
388*d14abf15SRobert Mustacchi                                   FALSE);
389*d14abf15SRobert Mustacchi     if (lm_status != LM_STATUS_SUCCESS)
390*d14abf15SRobert Mustacchi     {
391*d14abf15SRobert Mustacchi         return lm_status;
392*d14abf15SRobert Mustacchi     }
393*d14abf15SRobert Mustacchi 
394*d14abf15SRobert Mustacchi     //assign additional pbl members
395*d14abf15SRobert Mustacchi     bd_chain->pbl_phys_addr_table = pbl_phys_table;
396*d14abf15SRobert Mustacchi     bd_chain->pbl_virt_addr_table = pbl_virt_table;
397*d14abf15SRobert Mustacchi     bd_chain->b_is_chain_mode     = FALSE;
398*d14abf15SRobert Mustacchi     bd_chain->num_bd_to_sub       = 1;
399*d14abf15SRobert Mustacchi     bd_chain->usable_bds_mask     = bd_chain->usable_bds_per_page - 1;
400*d14abf15SRobert Mustacchi     // Upon first be consume or produce, page will be advanced,
401*d14abf15SRobert Mustacchi     // so set the initial page index to the last one
402*d14abf15SRobert Mustacchi     bd_chain->pbe_idx             = page_cnt - 1;
403*d14abf15SRobert Mustacchi 
404*d14abf15SRobert Mustacchi     lm_status = lm_bd_chain_pbl_set_ptrs(mem_virt,
405*d14abf15SRobert Mustacchi                                          mem_phys,
406*d14abf15SRobert Mustacchi                                          bd_chain->pbl_phys_addr_table,
407*d14abf15SRobert Mustacchi                                          bd_chain->pbl_virt_addr_table,
408*d14abf15SRobert Mustacchi                                          page_cnt);
409*d14abf15SRobert Mustacchi     if (lm_status != LM_STATUS_SUCCESS)
410*d14abf15SRobert Mustacchi     {
411*d14abf15SRobert Mustacchi         return lm_status;
412*d14abf15SRobert Mustacchi     }
413*d14abf15SRobert Mustacchi 
414*d14abf15SRobert Mustacchi     return LM_STATUS_SUCCESS;
415*d14abf15SRobert Mustacchi }
416*d14abf15SRobert Mustacchi 
417*d14abf15SRobert Mustacchi /** Description
418*d14abf15SRobert Mustacchi  *  Function resets a bd chain: initializes the bds to 'all zeros'
419*d14abf15SRobert Mustacchi  *  chain remains valid though, (last bd points to the next page of the bd chain)
420*d14abf15SRobert Mustacchi  */
lm_bd_chain_reset(struct _lm_device_t * pdev,lm_bd_chain_t * bd_chain)421*d14abf15SRobert Mustacchi __inline static void lm_bd_chain_reset(struct _lm_device_t * pdev, lm_bd_chain_t * bd_chain)
422*d14abf15SRobert Mustacchi {
423*d14abf15SRobert Mustacchi     DbgBreakIf(!bd_chain->bd_chain_virt);
424*d14abf15SRobert Mustacchi     /* FIXME: assumption that memory is contiguous.. */
425*d14abf15SRobert Mustacchi     mm_memset(bd_chain->bd_chain_virt, 0, bd_chain->page_cnt * LM_PAGE_SIZE);
426*d14abf15SRobert Mustacchi     if (bd_chain->b_is_chain_mode)
427*d14abf15SRobert Mustacchi     {
428*d14abf15SRobert Mustacchi         lm_bd_chain_setup(pdev,
429*d14abf15SRobert Mustacchi                           bd_chain,
430*d14abf15SRobert Mustacchi                           bd_chain->bd_chain_virt,
431*d14abf15SRobert Mustacchi                           bd_chain->bd_chain_phy,
432*d14abf15SRobert Mustacchi                           bd_chain->page_cnt,
433*d14abf15SRobert Mustacchi                           bd_chain->bd_size,
434*d14abf15SRobert Mustacchi                           FALSE,
435*d14abf15SRobert Mustacchi                           bd_chain->b_is_chain_mode);
436*d14abf15SRobert Mustacchi     }
437*d14abf15SRobert Mustacchi     else
438*d14abf15SRobert Mustacchi     {
439*d14abf15SRobert Mustacchi         lm_bd_chain_pbl_setup(pdev,
440*d14abf15SRobert Mustacchi                               bd_chain,
441*d14abf15SRobert Mustacchi                               bd_chain->bd_chain_virt,
442*d14abf15SRobert Mustacchi                               bd_chain->bd_chain_phy,
443*d14abf15SRobert Mustacchi                               bd_chain->pbl_virt_addr_table,
444*d14abf15SRobert Mustacchi                               bd_chain->pbl_phys_addr_table,
445*d14abf15SRobert Mustacchi                               bd_chain->page_cnt,
446*d14abf15SRobert Mustacchi                               bd_chain->bd_size,
447*d14abf15SRobert Mustacchi                               FALSE);
448*d14abf15SRobert Mustacchi     }
449*d14abf15SRobert Mustacchi }
450*d14abf15SRobert Mustacchi 
451*d14abf15SRobert Mustacchi /* Receives a bd_idx, pointer to bd and increases them.
452*d14abf15SRobert Mustacchi  * the physical address is the physical address of the base of the page
453*d14abf15SRobert Mustacchi  * Assumptions:
454*d14abf15SRobert Mustacchi  * - virt is initialized with the virtual address of the current bd
455*d14abf15SRobert Mustacchi  * - phys is initialized with the physical address of the current page
456*d14abf15SRobert Mustacchi  */
lm_bd_chain_incr_bd(lm_bd_chain_t * bd_chain,lm_address_t * phys,void ** virt,u16_t * bd_idx)457*d14abf15SRobert Mustacchi __inline static void lm_bd_chain_incr_bd(
458*d14abf15SRobert Mustacchi     lm_bd_chain_t     * bd_chain,
459*d14abf15SRobert Mustacchi     lm_address_t      * phys,
460*d14abf15SRobert Mustacchi     void             ** virt,
461*d14abf15SRobert Mustacchi     u16_t             * bd_idx)
462*d14abf15SRobert Mustacchi {
463*d14abf15SRobert Mustacchi 
464*d14abf15SRobert Mustacchi     (*bd_idx)++;
465*d14abf15SRobert Mustacchi     *virt = ((char *)*virt) + bd_chain->bd_size;
466*d14abf15SRobert Mustacchi 
467*d14abf15SRobert Mustacchi     if((*bd_idx & bd_chain->usable_bds_per_page) == bd_chain->usable_bds_per_page) {
468*d14abf15SRobert Mustacchi         if (bd_chain->b_is_chain_mode) {
469*d14abf15SRobert Mustacchi             lm_bd_chain_next *next_bd = (lm_bd_chain_next *)(*virt);
470*d14abf15SRobert Mustacchi             (*bd_idx) += bd_chain->bds_skip_eop;
471*d14abf15SRobert Mustacchi              *virt = *(void **)(next_bd->reserved);
472*d14abf15SRobert Mustacchi              phys->as_u32.high = next_bd->addr_hi;
473*d14abf15SRobert Mustacchi              phys->as_u32.low  = next_bd->addr_lo;
474*d14abf15SRobert Mustacchi         } else {
475*d14abf15SRobert Mustacchi             //TODO: currently TOE only, implement for PBL
476*d14abf15SRobert Mustacchi             DbgBreak();
477*d14abf15SRobert Mustacchi         }
478*d14abf15SRobert Mustacchi     }
479*d14abf15SRobert Mustacchi 
480*d14abf15SRobert Mustacchi }
481*d14abf15SRobert Mustacchi 
lm_bd_advance_page(lm_bd_chain_t * bd_chain,u16_t * idx_to_inc)482*d14abf15SRobert Mustacchi __inline static void lm_bd_advance_page(lm_bd_chain_t* bd_chain, u16_t *idx_to_inc)
483*d14abf15SRobert Mustacchi {
484*d14abf15SRobert Mustacchi     if (bd_chain->b_is_chain_mode)
485*d14abf15SRobert Mustacchi     {
486*d14abf15SRobert Mustacchi         lm_bd_chain_next *next_bd = (lm_bd_chain_next *)bd_chain->next_bd;
487*d14abf15SRobert Mustacchi         bd_chain->next_bd = *(void **)(next_bd->reserved);
488*d14abf15SRobert Mustacchi         *idx_to_inc += bd_chain->bds_skip_eop;
489*d14abf15SRobert Mustacchi     }
490*d14abf15SRobert Mustacchi     else
491*d14abf15SRobert Mustacchi     {
492*d14abf15SRobert Mustacchi         bd_chain->pbe_idx++;
493*d14abf15SRobert Mustacchi         if (bd_chain->pbe_idx == bd_chain->page_cnt) {
494*d14abf15SRobert Mustacchi             bd_chain->pbe_idx = 0;
495*d14abf15SRobert Mustacchi         }
496*d14abf15SRobert Mustacchi         bd_chain->next_bd = *(void **)((u8_t *)bd_chain->pbl_virt_addr_table + (sizeof(void *) * bd_chain->pbe_idx));
497*d14abf15SRobert Mustacchi     }
498*d14abf15SRobert Mustacchi }
499*d14abf15SRobert Mustacchi 
500*d14abf15SRobert Mustacchi /*******************************************************************************
501*d14abf15SRobert Mustacchi * API For a bd-chain that the driver "Produces"
502*d14abf15SRobert Mustacchi *******************************************************************************/
503*d14abf15SRobert Mustacchi 
504*d14abf15SRobert Mustacchi /* update bds availabily.
505*d14abf15SRobert Mustacchi  * - nbds - number of _usable_ consumed bds
506*d14abf15SRobert Mustacchi  * - NOTE: the chain consumer idx+pointer are not maintained! */
lm_bd_chain_bds_consumed(lm_bd_chain_t * bd_chain,u16_t nbds)507*d14abf15SRobert Mustacchi __inline static void lm_bd_chain_bds_consumed(lm_bd_chain_t* bd_chain, u16_t nbds)
508*d14abf15SRobert Mustacchi {
509*d14abf15SRobert Mustacchi     bd_chain->bd_left += nbds;
510*d14abf15SRobert Mustacchi     DbgBreakIfFastPath(bd_chain->bd_left > bd_chain->capacity);
511*d14abf15SRobert Mustacchi }
512*d14abf15SRobert Mustacchi 
513*d14abf15SRobert Mustacchi /* returns ptr to next _usable_ bd to be produced,
514*d14abf15SRobert Mustacchi  * decreases bds availability by 1, and updates prod idx.
515*d14abf15SRobert Mustacchi  * NOTE: special case for TOE: prod idx jumps to the next page only when the first bd of the next page is produced */
lm_toe_bd_chain_produce_bd(lm_bd_chain_t * bd_chain)516*d14abf15SRobert Mustacchi __inline static void *lm_toe_bd_chain_produce_bd(lm_bd_chain_t* bd_chain)
517*d14abf15SRobert Mustacchi {
518*d14abf15SRobert Mustacchi     void *ret_bd = NULL;
519*d14abf15SRobert Mustacchi     u16_t prod_idx = 0;
520*d14abf15SRobert Mustacchi 
521*d14abf15SRobert Mustacchi     DbgBreakIf(!bd_chain->bd_left);
522*d14abf15SRobert Mustacchi 
523*d14abf15SRobert Mustacchi     prod_idx = bd_chain->prod_idx - bd_chain->num_bd_to_sub;
524*d14abf15SRobert Mustacchi     if((prod_idx & bd_chain->usable_bds_mask) == bd_chain->usable_bds_mask) {
525*d14abf15SRobert Mustacchi         lm_bd_advance_page(bd_chain, &bd_chain->prod_idx);
526*d14abf15SRobert Mustacchi     }
527*d14abf15SRobert Mustacchi 
528*d14abf15SRobert Mustacchi     ret_bd = bd_chain->next_bd;
529*d14abf15SRobert Mustacchi     bd_chain->bd_left--;
530*d14abf15SRobert Mustacchi     bd_chain->prod_idx++;
531*d14abf15SRobert Mustacchi     bd_chain->next_bd += bd_chain->bd_size;
532*d14abf15SRobert Mustacchi 
533*d14abf15SRobert Mustacchi     return ret_bd;
534*d14abf15SRobert Mustacchi }
535*d14abf15SRobert Mustacchi 
536*d14abf15SRobert Mustacchi /* returns ptr to next _usable_ bd to be produced,
537*d14abf15SRobert Mustacchi  * decreases bds availability by 1, and updates prod idx.
538*d14abf15SRobert Mustacchi  */
lm_bd_chain_produce_bd(lm_bd_chain_t * bd_chain)539*d14abf15SRobert Mustacchi __inline static void *lm_bd_chain_produce_bd(lm_bd_chain_t* bd_chain)
540*d14abf15SRobert Mustacchi {
541*d14abf15SRobert Mustacchi     void *ret_bd = NULL;
542*d14abf15SRobert Mustacchi     u16_t prod_idx = 0;
543*d14abf15SRobert Mustacchi 
544*d14abf15SRobert Mustacchi     DbgBreakIfFastPath(!bd_chain->bd_left);
545*d14abf15SRobert Mustacchi 
546*d14abf15SRobert Mustacchi     ret_bd = bd_chain->next_bd;
547*d14abf15SRobert Mustacchi     bd_chain->bd_left--;
548*d14abf15SRobert Mustacchi     bd_chain->prod_idx++;
549*d14abf15SRobert Mustacchi     bd_chain->next_bd += bd_chain->bd_size;
550*d14abf15SRobert Mustacchi 
551*d14abf15SRobert Mustacchi     prod_idx = bd_chain->prod_idx - bd_chain->num_bd_to_sub;
552*d14abf15SRobert Mustacchi     if((prod_idx & bd_chain->usable_bds_mask) == bd_chain->usable_bds_mask) {
553*d14abf15SRobert Mustacchi         lm_bd_advance_page(bd_chain, &bd_chain->prod_idx);
554*d14abf15SRobert Mustacchi     }
555*d14abf15SRobert Mustacchi 
556*d14abf15SRobert Mustacchi     return ret_bd;
557*d14abf15SRobert Mustacchi }
558*d14abf15SRobert Mustacchi 
559*d14abf15SRobert Mustacchi 
560*d14abf15SRobert Mustacchi /*******************************************************************************
561*d14abf15SRobert Mustacchi * API For a bd-chain that the driver "Consumes"
562*d14abf15SRobert Mustacchi *******************************************************************************/
563*d14abf15SRobert Mustacchi 
564*d14abf15SRobert Mustacchi /* returns ptr to next _usable_ bd to be consume,
565*d14abf15SRobert Mustacchi  * increases bds availability by 1, and updates cons idx.
566*d14abf15SRobert Mustacchi  * NOTE: cons idx jumps to the next page only when the first bd of the next page is consumed */
lm_toe_bd_chain_consume_bd(lm_bd_chain_t * bd_chain)567*d14abf15SRobert Mustacchi __inline static void *lm_toe_bd_chain_consume_bd(lm_bd_chain_t* bd_chain)
568*d14abf15SRobert Mustacchi {
569*d14abf15SRobert Mustacchi     void *ret_bd = NULL;
570*d14abf15SRobert Mustacchi     u16_t cons_idx = 0;
571*d14abf15SRobert Mustacchi 
572*d14abf15SRobert Mustacchi     DbgBreakIf(bd_chain->bd_left == bd_chain->capacity);
573*d14abf15SRobert Mustacchi 
574*d14abf15SRobert Mustacchi     cons_idx = bd_chain->cons_idx - bd_chain->num_bd_to_sub;
575*d14abf15SRobert Mustacchi     if((cons_idx & bd_chain->usable_bds_mask) == bd_chain->usable_bds_mask) {
576*d14abf15SRobert Mustacchi         lm_bd_advance_page(bd_chain, &bd_chain->cons_idx);
577*d14abf15SRobert Mustacchi     }
578*d14abf15SRobert Mustacchi     ret_bd = bd_chain->next_bd;
579*d14abf15SRobert Mustacchi 
580*d14abf15SRobert Mustacchi     bd_chain->bd_left++;
581*d14abf15SRobert Mustacchi     bd_chain->cons_idx++;
582*d14abf15SRobert Mustacchi     bd_chain->next_bd += bd_chain->bd_size;
583*d14abf15SRobert Mustacchi 
584*d14abf15SRobert Mustacchi     return ret_bd;
585*d14abf15SRobert Mustacchi }
586*d14abf15SRobert Mustacchi 
lm_bd_chain_consume_bd(lm_bd_chain_t * bd_chain)587*d14abf15SRobert Mustacchi __inline static void *lm_bd_chain_consume_bd(lm_bd_chain_t* bd_chain)
588*d14abf15SRobert Mustacchi {
589*d14abf15SRobert Mustacchi     void *ret_bd = NULL;
590*d14abf15SRobert Mustacchi     u16_t cons_idx = 0;
591*d14abf15SRobert Mustacchi 
592*d14abf15SRobert Mustacchi     DbgBreakIfFastPath(bd_chain->bd_left == bd_chain->capacity);
593*d14abf15SRobert Mustacchi 
594*d14abf15SRobert Mustacchi     ret_bd = bd_chain->next_bd;
595*d14abf15SRobert Mustacchi 
596*d14abf15SRobert Mustacchi     bd_chain->bd_left++;
597*d14abf15SRobert Mustacchi     bd_chain->cons_idx++;
598*d14abf15SRobert Mustacchi     bd_chain->next_bd += bd_chain->bd_size;
599*d14abf15SRobert Mustacchi 
600*d14abf15SRobert Mustacchi     cons_idx = bd_chain->cons_idx - bd_chain->num_bd_to_sub;
601*d14abf15SRobert Mustacchi     if((cons_idx & bd_chain->usable_bds_mask) == bd_chain->usable_bds_mask) {
602*d14abf15SRobert Mustacchi         lm_bd_advance_page(bd_chain, &bd_chain->cons_idx);
603*d14abf15SRobert Mustacchi     }
604*d14abf15SRobert Mustacchi 
605*d14abf15SRobert Mustacchi     return ret_bd;
606*d14abf15SRobert Mustacchi }
607*d14abf15SRobert Mustacchi 
608*d14abf15SRobert Mustacchi /* returns a bd only if it is contiguous to the previously requested bd... otherwise NULL.
609*d14abf15SRobert Mustacchi  * The algorithm is based on the fact that we don't double-increase a consumer if we've reached the
610*d14abf15SRobert Mustacchi  * end of the page. we have one call that is called when the next_bd points to the last_bd, in which case
611*d14abf15SRobert Mustacchi  * we recognize that the next_bd is no longer contiguous, return NULL and move forward. The next call will
612*d14abf15SRobert Mustacchi  * return the next bd...
613*d14abf15SRobert Mustacchi  */
lm_bd_chain_consume_bd_contiguous(lm_bd_chain_t * bd_chain)614*d14abf15SRobert Mustacchi __inline static void *lm_bd_chain_consume_bd_contiguous(lm_bd_chain_t* bd_chain)
615*d14abf15SRobert Mustacchi {
616*d14abf15SRobert Mustacchi     void *ret_bd = NULL;
617*d14abf15SRobert Mustacchi     u16_t cons_idx = 0;
618*d14abf15SRobert Mustacchi 
619*d14abf15SRobert Mustacchi     DbgBreakIf(bd_chain->bd_left == bd_chain->capacity);
620*d14abf15SRobert Mustacchi 
621*d14abf15SRobert Mustacchi     cons_idx = bd_chain->cons_idx - bd_chain->num_bd_to_sub;
622*d14abf15SRobert Mustacchi     if((cons_idx & bd_chain->usable_bds_mask) == bd_chain->usable_bds_mask) {
623*d14abf15SRobert Mustacchi         lm_bd_advance_page(bd_chain, &bd_chain->cons_idx);
624*d14abf15SRobert Mustacchi 
625*d14abf15SRobert Mustacchi         return NULL; /* we've just skipped the last bd... */
626*d14abf15SRobert Mustacchi     }
627*d14abf15SRobert Mustacchi 
628*d14abf15SRobert Mustacchi     ret_bd = bd_chain->next_bd;
629*d14abf15SRobert Mustacchi 
630*d14abf15SRobert Mustacchi     bd_chain->bd_left++;
631*d14abf15SRobert Mustacchi     bd_chain->cons_idx++;
632*d14abf15SRobert Mustacchi     bd_chain->next_bd += bd_chain->bd_size;
633*d14abf15SRobert Mustacchi 
634*d14abf15SRobert Mustacchi     return ret_bd;
635*d14abf15SRobert Mustacchi }
636*d14abf15SRobert Mustacchi 
637*d14abf15SRobert Mustacchi 
638*d14abf15SRobert Mustacchi 
639*d14abf15SRobert Mustacchi /* update bds availabily and prod idx.
640*d14abf15SRobert Mustacchi  * - nbds - number of _usable_ produced bds
641*d14abf15SRobert Mustacchi  * Special case for TOE, they need producer increased only if we've moved to the next page...  */
lm_toe_bd_chain_bds_produced(lm_bd_chain_t * bd_chain,u16_t nbds)642*d14abf15SRobert Mustacchi __inline static void lm_toe_bd_chain_bds_produced(lm_bd_chain_t* bd_chain, u16_t nbds)
643*d14abf15SRobert Mustacchi {
644*d14abf15SRobert Mustacchi     u16_t nbds_mod_usable_bds;
645*d14abf15SRobert Mustacchi     u8_t next_bds = 0;
646*d14abf15SRobert Mustacchi 
647*d14abf15SRobert Mustacchi     DbgBreakIfFastPath(bd_chain->bd_left < nbds);
648*d14abf15SRobert Mustacchi     bd_chain->bd_left -= nbds;
649*d14abf15SRobert Mustacchi 
650*d14abf15SRobert Mustacchi    /* perform the operation "nbds % bd_chain->usable_bds_per_page" manually
651*d14abf15SRobert Mustacchi    (in order to avoid explicit modulo instruction that lead to very
652*d14abf15SRobert Mustacchi     expensive IDIV asm instruction) */
653*d14abf15SRobert Mustacchi     nbds_mod_usable_bds = nbds;
654*d14abf15SRobert Mustacchi     while (nbds_mod_usable_bds >= bd_chain->usable_bds_per_page)
655*d14abf15SRobert Mustacchi     {
656*d14abf15SRobert Mustacchi         nbds_mod_usable_bds -= bd_chain->usable_bds_per_page;
657*d14abf15SRobert Mustacchi     }
658*d14abf15SRobert Mustacchi 
659*d14abf15SRobert Mustacchi     /* calculate the number of _next_ bds passed */
660*d14abf15SRobert Mustacchi     next_bds += nbds / bd_chain->usable_bds_per_page;
661*d14abf15SRobert Mustacchi     if(next_bds && ((bd_chain->prod_idx & bd_chain->bds_per_page_mask) == 0)) {
662*d14abf15SRobert Mustacchi         next_bds--; /* special care here, this next bd will be counted only next time bds are produced */
663*d14abf15SRobert Mustacchi     }
664*d14abf15SRobert Mustacchi     if((bd_chain->prod_idx & bd_chain->bds_per_page_mask) + nbds_mod_usable_bds > bd_chain->usable_bds_per_page) {
665*d14abf15SRobert Mustacchi         next_bds++;
666*d14abf15SRobert Mustacchi     }
667*d14abf15SRobert Mustacchi 
668*d14abf15SRobert Mustacchi     /* update prod idx */
669*d14abf15SRobert Mustacchi     bd_chain->prod_idx += nbds + next_bds * bd_chain->bds_skip_eop;
670*d14abf15SRobert Mustacchi 
671*d14abf15SRobert Mustacchi     DbgBreakIfFastPath((bd_chain->prod_idx & bd_chain->bds_per_page_mask) > bd_chain->usable_bds_per_page); /* assertion relevant to 8b bd chain */
672*d14abf15SRobert Mustacchi     DbgBreakIfFastPath((bd_chain->prod_idx & bd_chain->bds_per_page_mask) == 0); /* GilR 5/13/2006 - this is currently the agreement with FW */
673*d14abf15SRobert Mustacchi }
674*d14abf15SRobert Mustacchi 
675*d14abf15SRobert Mustacchi /* update bds availabily and prod idx.
676*d14abf15SRobert Mustacchi  * - nbds - number of _usable_ produced bds */
lm_bd_chain_bds_produced(lm_bd_chain_t * bd_chain,u16_t nbds)677*d14abf15SRobert Mustacchi __inline static void lm_bd_chain_bds_produced(lm_bd_chain_t* bd_chain, u16_t nbds)
678*d14abf15SRobert Mustacchi {
679*d14abf15SRobert Mustacchi     u16_t nbds_mod_usable_bds;
680*d14abf15SRobert Mustacchi     u8_t next_bds = 0;
681*d14abf15SRobert Mustacchi 
682*d14abf15SRobert Mustacchi     DbgBreakIfFastPath(bd_chain->bd_left < nbds);
683*d14abf15SRobert Mustacchi     bd_chain->bd_left -= nbds;
684*d14abf15SRobert Mustacchi 
685*d14abf15SRobert Mustacchi     /* perform the operation "nbds % bd_chain->usable_bds_per_page" manually
686*d14abf15SRobert Mustacchi    (in order to avoid explicit modulo instruction that lead to very
687*d14abf15SRobert Mustacchi     expensive IDIV asm instruction) */
688*d14abf15SRobert Mustacchi     nbds_mod_usable_bds = nbds;
689*d14abf15SRobert Mustacchi     while (nbds_mod_usable_bds >= bd_chain->usable_bds_per_page)
690*d14abf15SRobert Mustacchi     {
691*d14abf15SRobert Mustacchi         nbds_mod_usable_bds -= bd_chain->usable_bds_per_page;
692*d14abf15SRobert Mustacchi     }
693*d14abf15SRobert Mustacchi 
694*d14abf15SRobert Mustacchi     /* calculate the number of _next_ bds passed */
695*d14abf15SRobert Mustacchi     next_bds += nbds / bd_chain->usable_bds_per_page;
696*d14abf15SRobert Mustacchi     if((bd_chain->prod_idx & bd_chain->bds_per_page_mask) + nbds_mod_usable_bds > bd_chain->usable_bds_per_page) {
697*d14abf15SRobert Mustacchi         next_bds++;
698*d14abf15SRobert Mustacchi     }
699*d14abf15SRobert Mustacchi 
700*d14abf15SRobert Mustacchi     /* update prod idx */
701*d14abf15SRobert Mustacchi     bd_chain->prod_idx += nbds + next_bds * bd_chain->bds_skip_eop;
702*d14abf15SRobert Mustacchi }
703*d14abf15SRobert Mustacchi 
704*d14abf15SRobert Mustacchi /* lm_bd_chain_bd_produced -
705*d14abf15SRobert Mustacchi    a performance optimated version of lm_bd_chain_bds_produced:
706*d14abf15SRobert Mustacchi    update bds availabily and prod idx, when only one bd is produced.
707*d14abf15SRobert Mustacchi  */
lm_bd_chain_bd_produced(lm_bd_chain_t * bd_chain)708*d14abf15SRobert Mustacchi __inline static void lm_bd_chain_bd_produced(lm_bd_chain_t* bd_chain)
709*d14abf15SRobert Mustacchi {
710*d14abf15SRobert Mustacchi     DbgBreakIfFastPath(bd_chain->bd_left < 1);
711*d14abf15SRobert Mustacchi     bd_chain->bd_left--;
712*d14abf15SRobert Mustacchi 
713*d14abf15SRobert Mustacchi     /* if we passed a _next_ bd, increase prod_idx accordingly */
714*d14abf15SRobert Mustacchi     if((bd_chain->prod_idx & bd_chain->bds_per_page_mask) + 1 > bd_chain->usable_bds_per_page) {
715*d14abf15SRobert Mustacchi         bd_chain->prod_idx += bd_chain->bds_skip_eop;
716*d14abf15SRobert Mustacchi     }
717*d14abf15SRobert Mustacchi 
718*d14abf15SRobert Mustacchi     /* update prod idx for the produced bd */
719*d14abf15SRobert Mustacchi     bd_chain->prod_idx++;
720*d14abf15SRobert Mustacchi }
721*d14abf15SRobert Mustacchi 
722*d14abf15SRobert Mustacchi /* TRUE if all params in bd_chains are equal but the pointers */
lm_bd_chains_are_consistent(lm_bd_chain_t * bd_chain,lm_bd_chain_t * bd_chain2)723*d14abf15SRobert Mustacchi __inline static u8_t lm_bd_chains_are_consistent( lm_bd_chain_t* bd_chain,
724*d14abf15SRobert Mustacchi                                                   lm_bd_chain_t* bd_chain2 )
725*d14abf15SRobert Mustacchi {
726*d14abf15SRobert Mustacchi     const u32_t cmp_size = OFFSETOF(lm_bd_chain_t, reserved) - OFFSETOF(lm_bd_chain_t, page_cnt) ;
727*d14abf15SRobert Mustacchi     u8_t        b_ret    = 0;
728*d14abf15SRobert Mustacchi 
729*d14abf15SRobert Mustacchi     ASSERT_STATIC( OFFSETOF(lm_bd_chain_t, page_cnt) < OFFSETOF(lm_bd_chain_t, reserved)) ;
730*d14abf15SRobert Mustacchi 
731*d14abf15SRobert Mustacchi     b_ret = mm_memcmp( (u8_t*)bd_chain + OFFSETOF(lm_bd_chain_t, page_cnt),
732*d14abf15SRobert Mustacchi                        (u8_t*)bd_chain2 + OFFSETOF(lm_bd_chain_t, page_cnt),
733*d14abf15SRobert Mustacchi                        cmp_size );
734*d14abf15SRobert Mustacchi 
735*d14abf15SRobert Mustacchi     return b_ret;
736*d14abf15SRobert Mustacchi }
737*d14abf15SRobert Mustacchi 
738*d14abf15SRobert Mustacchi #endif /* _BD_CHAIN_H */
739