upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / usb / host / s3c-otg / s3c-otg-scheduler-ischeduler.c
1 /****************************************************************************
2  *  (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
3  *
4  *  [File Name]   : Scheduler.c
5  *  [Description] : The source file implements the internal functions of Scheduler.
6  *  [Author]      : Yang Soon Yeal { syatom.yang@samsung.com }
7  *  [Department]  : System LSI Division/System SW Lab
8  *  [Created Date]: 2009/2/10
9  *  [Revision History]
10  *      (1) 2008/06/03   by Yang Soon Yeal { syatom.yang@samsung.com }
11  *          - Created this file and implements functions of Scheduler
12  *       -# Jul 15,2008 v1.2 by SeungSoo Yang (ss1.yang@samsung.com) \n
13  *                              : Optimizing for performance \n
14  *
15  ****************************************************************************/
16 /****************************************************************************
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 2 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30  ****************************************************************************/
31
32 #include "s3c-otg-scheduler-scheduler.h"
33
34 void init_scheduler(void)
35 {
36         /*init_scheduling();*/
37         init_transfer_ready_q();
38 }
39
40 /******************************************************************************/
41 /*!
42  * @name        int     reserve_used_resource_for_periodic(u32  usb_time)
43  *
44  * @brief               this function reserves the necessary resource of USB Transfer for Periodic Transfer.
45  *                      So, this function firstly checks there ares some available USB Time
46  *                      and Channel resource for USB Transfer.
47  *                      if there exists necessary resources for Periodic Transfer, then reserves the resource.
48  *
49  * @param       [IN]    usb_time        = indicates the USB Time for the USB Transfer.
50  *
51  * @return      USB_ERR_SUCCESS         -       if success to insert pInsertED to S3CScheduler.
52  *                      USB_ERR_NO_BANDWIDTH    -       if fail to reserve the USB Bandwidth.
53  *                      USB_ERR_NO_CHANNEL              -       if fail to reserve the Channel.
54  */
55 /******************************************************************************/
56
57 int     reserve_used_resource_for_periodic(u32 usb_time, u8 dev_speed, u8 trans_type)
58 {
59         if(inc_perio_bus_time(usb_time,dev_speed)==USB_ERR_SUCCESS) {
60                 if(inc_perio_chnum()==USB_ERR_SUCCESS) {
61                         otg_usbcore_inc_usb_bandwidth(usb_time);
62                         otg_usbcore_inc_periodic_transfer_cnt(trans_type);
63                         return USB_ERR_SUCCESS;
64                 }
65                 else {
66                         dec_perio_bus_time(usb_time);
67                         return USB_ERR_NO_CHANNEL;
68                 }
69         }
70         else {
71                 return USB_ERR_NO_BANDWIDTH;
72         }
73 }
74
75 /******************************************************************************/
76 /*!
77  * @name        int     free_usb_resource_for_periodic(ed_t *           pFreeED)
78  *
79  * @brief               this function frees the resources to be allocated to pFreeED at S3CScheduler.
80  *                      that is, this functions only releases the resources to be allocated by S3C6400Scheduler.
81  *
82  * @param       [IN]    pFreeED = indicates ed_t to have the information of the resource to be released.
83  *
84  * @return      USB_ERR_SUCCESS -       if success to free the USB Resource.
85  *                      USB_ERR_FAIL            -       if fail to free the USB Resrouce.
86  */
87 /******************************************************************************/
88 int     free_usb_resource_for_periodic(
89                 u32     free_usb_time, u8 free_chnum, u8 trans_type)
90 {
91         if(dec_perio_bus_time(free_usb_time)==USB_ERR_SUCCESS) {
92                 if(dec_perio_chnum()==USB_ERR_SUCCESS) {
93                         if(free_chnum!=CH_NONE) {
94                                 oci_channel_dealloc(free_chnum);
95                                 set_transferring_td_array(free_chnum, 0);
96                         }
97                         otg_usbcore_des_usb_bandwidth(free_usb_time);
98                         otg_usbcore_des_periodic_transfer_cnt(trans_type);
99                         return USB_ERR_SUCCESS;
100                 }
101         }
102         return USB_ERR_FAIL;
103 }
104
105 /******************************************************************************/
106 /*!
107  * @name        int     remove_ed_from_scheduler(ed_t * remove_ed)
108  *
109  * @brief               this function just remove the remove_ed from TransferReadyQ. So if you want to
110  *                      stop the USB Tranfer of remove_ed or release the releated resources.
111  *                      you should call another functions of S3CScheduler.
112  *
113  * @param       [IN]    remove_ed       = indicates ed_t to be removed from TransferReadyQ.
114  *
115  * @return      USB_ERR_SUCCESS -       if success to remove the remove_ed from TransferReadyQ.
116  *                      USB_ERR_FAIL            -       if fail to remove the remove_ed from TransferReadyQ.
117  */
118  /******************************************************************************/
119 int     remove_ed_from_scheduler(ed_t   *remove_ed)
120 {
121         if(remove_ed->ed_status.is_in_transfer_ready_q) {
122                 remove_ed_from_ready_q(remove_ed);
123                 remove_ed->ed_status.is_in_transfer_ready_q = false;
124
125                 return USB_ERR_SUCCESS;
126         }
127         else {
128                 return USB_ERR_FAIL;
129         }
130 }
131
132 /******************************************************************************/
133 /*!
134  * @name        int     cancel_to_transfer_td(struct sec_otghost *otghost, td_t *cancel_td)
135  *
136  * @brief               this function stop to execute the USB Transfer of cancel_td and
137  *                      release the Channel Resources to be allocated the cancel_td ,if the Transfer Type of
138  *                      cancel_td is NonPeriodic Transfer.
139  *                      this function don't release any usb resources(Channel, USB Bandwidth) for Periodic Transfer.
140  *                      if you want to release some usb resources for a periodic Transfer, you should call
141  *                      the free_usb_resource_for_periodic()
142  *
143  * @param       [IN]    cancel_td       =       indicates the td_t to be canceled.
144  *
145  * @return      USB_ERR_SUCCESS -       if success to cancel the USB Transfer of cancel_td.
146  *                      USB_ERR_FAIL            -       if fail to cancel the USB Transfer of cancel_td.
147  */
148  /******************************************************************************/
149 int cancel_to_transfer_td(struct sec_otghost *otghost, td_t *cancel_td)
150 {
151         if(cancel_td->is_transfer_done) {
152                 return USB_ERR_FAIL;
153         }
154
155         if(cancel_td->is_transferring) {
156                 int err;
157
158                 err = oci_stop_transfer(otghost, cancel_td->cur_stransfer.alloc_chnum);
159
160                 if(err == USB_ERR_SUCCESS) {
161                         set_transferring_td_array(cancel_td->cur_stransfer.alloc_chnum,0);
162
163                         cancel_td->cur_stransfer.alloc_chnum            =       CH_NONE;
164                         cancel_td->is_transferring                              =       false;
165                         cancel_td->parent_ed_p->ed_status.is_in_transferring    =       false;
166                         cancel_td->parent_ed_p->ed_status.in_transferring_td    =       0;
167                         cancel_td->parent_ed_p->is_need_to_insert_scheduler     =       true;
168
169                         if(cancel_td->cur_stransfer.ed_desc_p->endpoint_type == BULK_TRANSFER ||
170                                 cancel_td->cur_stransfer.ed_desc_p->endpoint_type == CONTROL_TRANSFER ) {
171                                 dec_nonperio_chnum();
172                         }
173                         return err;
174                 }
175                 else {
176                         return err;
177                 }
178         }
179         else {
180                 return USB_ERR_FAIL;
181         }
182         return USB_ERR_SUCCESS;
183 }
184
185
186 /******************************************************************************/
187 /*!
188  * @name        int     retransmit(struct sec_otghost *otghost, td_t *retrasmit_td)
189  *
190  * @brief               this function retransmits the retrasmit_td immediately.
191  *                      So, the Channel of pRetransmitted is reused for retransmittion.
192  *
193  * @param       [IN]    retrasmit_td    =       indicates the pointer ot the td_t to be retransmitted.
194  *
195  * @return      USB_ERR_SUCCESS -       if success to retransmit the retrasmit_td.
196  *                      USB_ERR_FAIL            -       if fail to retransmit the retrasmit_td.
197  */
198  /******************************************************************************/
199 int retransmit(struct sec_otghost *otghost, td_t *retrasmit_td)
200 {
201         u32 td_addr=0;
202
203         if(get_transferring_td_array(retrasmit_td->cur_stransfer.alloc_chnum,&td_addr)==USB_ERR_SUCCESS) {
204                 if(td_addr == (u32)retrasmit_td) {
205                         if(oci_start_transfer(otghost, &retrasmit_td->cur_stransfer)
206                                         == retrasmit_td->cur_stransfer.alloc_chnum) {
207                                 retrasmit_td->is_transferring                           = true;
208                                 retrasmit_td->parent_ed_p->ed_status.in_transferring_td         = (u32)retrasmit_td;
209                                 retrasmit_td->parent_ed_p->ed_status.is_in_transfer_ready_q     = false;
210                                 retrasmit_td->parent_ed_p->ed_status.is_in_transferring = true;
211                         }
212                 }
213                 else {
214                         return  USB_ERR_FAIL;
215                 }
216         }
217         else {
218                 return  USB_ERR_FAIL;
219         }
220
221         return USB_ERR_SUCCESS;
222
223 }
224
225 /******************************************************************************/
226 /*!
227  * @name        int     reschedule(td_t         *reschedule_td)
228  *
229  * @brief               this function re-schedules the reschedule_td.
230  *                      So, the Channel of pRescheuleTD is released and reschedule_td is inserted to TransferReadyQ.
231  *
232  * @param       [IN]    reschedule_td   =       indicates the pointer ot the td_t to be rescheduled.
233  *
234  * @return      USB_ERR_SUCCESS -       if success to re-schedule the reschedule_td.
235  *                      USB_ERR_FAIL            -       if fail to re-schedule the reschedule_td.
236  */
237  /******************************************************************************/
238 int reschedule(td_t *reschedule_td)
239 {
240         u32     td_addr;
241
242         if(get_transferring_td_array(reschedule_td->cur_stransfer.alloc_chnum, &td_addr)==USB_ERR_SUCCESS)
243         {
244                 if((u32)reschedule_td == td_addr)
245                 {
246                         set_transferring_td_array(reschedule_td->cur_stransfer.alloc_chnum, 0);
247                         oci_channel_dealloc(reschedule_td->cur_stransfer.alloc_chnum);
248
249                         reschedule_td->cur_stransfer.alloc_chnum                        = CH_NONE;
250                         reschedule_td->parent_ed_p->is_need_to_insert_scheduler         = true;
251                         reschedule_td->parent_ed_p->ed_status.in_transferring_td        = 0;
252
253                         if(reschedule_td->parent_ed_p->ed_desc.endpoint_type == BULK_TRANSFER||
254                                 reschedule_td->parent_ed_p->ed_desc.endpoint_type == CONTROL_TRANSFER )
255                         {
256                                 /* Increase the available Channel */
257                                 dec_nonperio_chnum();
258
259                         }
260
261                         insert_ed_to_ready_q(reschedule_td->parent_ed_p, false);
262                         reschedule_td->parent_ed_p->ed_status.is_in_transfer_ready_q    =true;
263
264                 }
265                 else
266                 {
267                         /* this case is not support.... */
268                 }
269         }
270
271         return USB_ERR_SUCCESS;
272 }
273
274 /******************************************************************************/
275 /*!
276  * @name        int     deallocate(td_t         *deallocate_td)
277  *
278  * @brief               this function frees resources to be allocated deallocate_td by S3CScheduler.
279  *                      this function just free the resource by S3CScheduler. that is, Channel Resource.
280  *                      if there are another td_t at ed_t, deallocate() insert the ed_t to TransferReadyQ.
281  *
282  * @param       [IN]    deallocate_td   =       indicates the pointer ot the td_t to be deallocated.
283  *
284  * @return      USB_ERR_SUCCESS -       if success to dealloate the resources for the deallocate_td.
285  *                      USB_ERR_FAIL            -       if fail to dealloate the resources for the deallocate_td.
286  */
287  /******************************************************************************/
288 int     deallocate(td_t         *deallocate_td)
289 {
290         u32 td_addr;
291
292         if(get_transferring_td_array(deallocate_td->cur_stransfer.alloc_chnum , &td_addr)==USB_ERR_SUCCESS)
293         {
294                 if((u32)deallocate_td == td_addr)
295                 {
296                         set_transferring_td_array(deallocate_td->cur_stransfer.alloc_chnum, 0);
297                         oci_channel_dealloc(deallocate_td->cur_stransfer.alloc_chnum);
298
299                         deallocate_td->cur_stransfer.alloc_chnum = CH_NONE;
300
301                         if(deallocate_td->parent_ed_p->ed_desc.endpoint_type == BULK_TRANSFER||
302                                 deallocate_td->parent_ed_p->ed_desc.endpoint_type == CONTROL_TRANSFER )
303                         {
304                                 /* Increase the available Channel */
305                                 dec_nonperio_chnum();
306                         }
307
308                         deallocate_td->parent_ed_p->is_need_to_insert_scheduler = true;
309
310                         if(deallocate_td->parent_ed_p->num_td)
311                         {
312                                 /* insert ed_t to TransferReadyQ. */
313                                 insert_ed_to_ready_q(deallocate_td->parent_ed_p , false);
314                                 deallocate_td->parent_ed_p->ed_status.is_in_transfer_ready_q    = true;
315                                 deallocate_td->parent_ed_p->is_need_to_insert_scheduler                         = false;
316                         }
317                         return USB_ERR_SUCCESS;
318                 }
319                 else
320                 {
321                         return USB_ERR_FAIL;
322                 }
323         }
324         else
325         {
326                         return USB_ERR_FAIL;
327         }
328
329 }
330
331 /* TBD.... */
332 void do_schedule(struct sec_otghost *otghost)
333 {
334         if(get_avail_chnum()) {
335                 do_periodic_schedule(otghost);
336                 do_nonperiodic_schedule(otghost);
337         }
338 }
339
340 /******************************************************************************/
341 /*!
342  * @name        int     get_td_info(u8          chnum,
343  *                              unsigned int    *td_addr_p)
344  *
345  * @brief               this function returns the pointer of td_t at TransferringTDArray[chnum]
346  *
347  * @param       [IN]    chnum   = indicates the index of TransferringTDArray
348  *                                      to include the address of td_t which we gets
349  *              [OUT]   td_addr_p= indicate pointer to store the address of td_t.
350  *
351  * @return      USB_ERR_SUCCESS -if success to get the address of td_t.
352  *              USB_ERR_FAIL            -if fail to get the address of td_t.
353  */
354  /******************************************************************************/
355 int     get_td_info(    u8              chnum,
356                         unsigned int    *td_addr_p)
357 {
358         u32     td_addr;
359
360         if(get_transferring_td_array(chnum, &td_addr)==USB_ERR_SUCCESS)
361         {
362                 *td_addr_p = td_addr;
363                 return USB_ERR_SUCCESS;
364         }
365
366         return USB_ERR_FAIL;
367 }
368
369