1 /****************************************************************************
2 * (C) Copyright 2008 Samsung Electronics Co., Ltd., All rights reserved
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
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
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.
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.
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 ****************************************************************************/
32 #include "s3c-otg-scheduler-scheduler.h"
34 void init_scheduler(void)
36 /*init_scheduling();*/
37 init_transfer_ready_q();
40 /******************************************************************************/
42 * @name int reserve_used_resource_for_periodic(u32 usb_time)
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.
49 * @param [IN] usb_time = indicates the USB Time for the USB Transfer.
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.
55 /******************************************************************************/
57 int reserve_used_resource_for_periodic(u32 usb_time, u8 dev_speed, u8 trans_type)
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;
66 dec_perio_bus_time(usb_time);
67 return USB_ERR_NO_CHANNEL;
71 return USB_ERR_NO_BANDWIDTH;
75 /******************************************************************************/
77 * @name int free_usb_resource_for_periodic(ed_t * pFreeED)
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.
82 * @param [IN] pFreeED = indicates ed_t to have the information of the resource to be released.
84 * @return USB_ERR_SUCCESS - if success to free the USB Resource.
85 * USB_ERR_FAIL - if fail to free the USB Resrouce.
87 /******************************************************************************/
88 int free_usb_resource_for_periodic(
89 u32 free_usb_time, u8 free_chnum, u8 trans_type)
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);
97 otg_usbcore_des_usb_bandwidth(free_usb_time);
98 otg_usbcore_des_periodic_transfer_cnt(trans_type);
99 return USB_ERR_SUCCESS;
105 /******************************************************************************/
107 * @name int remove_ed_from_scheduler(ed_t * remove_ed)
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.
113 * @param [IN] remove_ed = indicates ed_t to be removed from TransferReadyQ.
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.
118 /******************************************************************************/
119 int remove_ed_from_scheduler(ed_t *remove_ed)
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;
125 return USB_ERR_SUCCESS;
132 /******************************************************************************/
134 * @name int cancel_to_transfer_td(struct sec_otghost *otghost, td_t *cancel_td)
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()
143 * @param [IN] cancel_td = indicates the td_t to be canceled.
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.
148 /******************************************************************************/
149 int cancel_to_transfer_td(struct sec_otghost *otghost, td_t *cancel_td)
151 if(cancel_td->is_transfer_done) {
155 if(cancel_td->is_transferring) {
158 err = oci_stop_transfer(otghost, cancel_td->cur_stransfer.alloc_chnum);
160 if(err == USB_ERR_SUCCESS) {
161 set_transferring_td_array(cancel_td->cur_stransfer.alloc_chnum,0);
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;
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();
182 return USB_ERR_SUCCESS;
186 /******************************************************************************/
188 * @name int retransmit(struct sec_otghost *otghost, td_t *retrasmit_td)
190 * @brief this function retransmits the retrasmit_td immediately.
191 * So, the Channel of pRetransmitted is reused for retransmittion.
193 * @param [IN] retrasmit_td = indicates the pointer ot the td_t to be retransmitted.
195 * @return USB_ERR_SUCCESS - if success to retransmit the retrasmit_td.
196 * USB_ERR_FAIL - if fail to retransmit the retrasmit_td.
198 /******************************************************************************/
199 int retransmit(struct sec_otghost *otghost, td_t *retrasmit_td)
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;
221 return USB_ERR_SUCCESS;
225 /******************************************************************************/
227 * @name int reschedule(td_t *reschedule_td)
229 * @brief this function re-schedules the reschedule_td.
230 * So, the Channel of pRescheuleTD is released and reschedule_td is inserted to TransferReadyQ.
232 * @param [IN] reschedule_td = indicates the pointer ot the td_t to be rescheduled.
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.
237 /******************************************************************************/
238 int reschedule(td_t *reschedule_td)
242 if(get_transferring_td_array(reschedule_td->cur_stransfer.alloc_chnum, &td_addr)==USB_ERR_SUCCESS)
244 if((u32)reschedule_td == td_addr)
246 set_transferring_td_array(reschedule_td->cur_stransfer.alloc_chnum, 0);
247 oci_channel_dealloc(reschedule_td->cur_stransfer.alloc_chnum);
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;
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 )
256 /* Increase the available Channel */
257 dec_nonperio_chnum();
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;
267 /* this case is not support.... */
271 return USB_ERR_SUCCESS;
274 /******************************************************************************/
276 * @name int deallocate(td_t *deallocate_td)
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.
282 * @param [IN] deallocate_td = indicates the pointer ot the td_t to be deallocated.
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.
287 /******************************************************************************/
288 int deallocate(td_t *deallocate_td)
292 if(get_transferring_td_array(deallocate_td->cur_stransfer.alloc_chnum , &td_addr)==USB_ERR_SUCCESS)
294 if((u32)deallocate_td == td_addr)
296 set_transferring_td_array(deallocate_td->cur_stransfer.alloc_chnum, 0);
297 oci_channel_dealloc(deallocate_td->cur_stransfer.alloc_chnum);
299 deallocate_td->cur_stransfer.alloc_chnum = CH_NONE;
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 )
304 /* Increase the available Channel */
305 dec_nonperio_chnum();
308 deallocate_td->parent_ed_p->is_need_to_insert_scheduler = true;
310 if(deallocate_td->parent_ed_p->num_td)
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;
317 return USB_ERR_SUCCESS;
332 void do_schedule(struct sec_otghost *otghost)
334 if(get_avail_chnum()) {
335 do_periodic_schedule(otghost);
336 do_nonperiodic_schedule(otghost);
340 /******************************************************************************/
342 * @name int get_td_info(u8 chnum,
343 * unsigned int *td_addr_p)
345 * @brief this function returns the pointer of td_t at TransferringTDArray[chnum]
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.
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.
354 /******************************************************************************/
355 int get_td_info( u8 chnum,
356 unsigned int *td_addr_p)
360 if(get_transferring_td_array(chnum, &td_addr)==USB_ERR_SUCCESS)
362 *td_addr_p = td_addr;
363 return USB_ERR_SUCCESS;