- Main Page
- Related Pages
- Data Structures
- Files

- File List
- Globals

# drivers/block/aesblk.c

Go to the documentation of this file.

    00001
    00045 #include <buffer.h>
    00046 #include <debug.h>
    00047 #include <dmapool.h>
    00048 #include <interrupt.h>
    00049 #include <workqueue.h>
    00050 #include <timer_tc.h>
    00051 #include <board/init.h>
    00052 #include <chip/memory-map.h>
    00053 #include <chip/clk.h>
    00054 #include <block/device.h>
    00055 #include <status-codes.h>
    00056 #include <malloc.h>
    00057 #include <string.h>
    00058 #include <aes.h>
    00059 #include <atomic.h>
    00060 #include <block/aesblk.h>
    00061
    00062 static void aesblk_worker(void *data);
    00063
    00073 void aesblk_init(struct aes_block_device *abdev,
    00074                 struct block_device *card_bdev)
    00075 {
    00076         struct block_device     *bdev;
    00077
    00078         bdev = &abdev->bdev;
    00079         abdev->card_bdev = card_bdev;
    00080
    00081         bdev->prepare_req = aesblk_prepare_req;
    00082         bdev->alloc_req = aesblk_alloc_req;
    00083         bdev->free_req = aesblk_free_req;
    00084 }
    00085
    00091 void aesblk_update(struct aes_block_device *abdev)
    00092 {
    00093         struct block_device *bdev = &abdev->bdev;
    00094         struct block_device *card_bdev = abdev->card_bdev;
    00095
    00096         bdev->block_size = card_bdev->block_size;
    00097         bdev->nr_blocks = card_bdev->nr_blocks;
    00098         bdev->flags = card_bdev->flags;
    00099         bdev->get_dev_id = card_bdev->get_dev_id;
    00100 }
    00101
    00102 static inline struct aes_block_device *bdev_to_abdev(
    00103                 struct block_device *bdev)
    00104 {
    00105         return container_of(bdev, struct aes_block_device, bdev);
    00106 }
    00107
    00108 static inline struct aes_block_request *abreq_of(
    00109                 struct block_request *req)
    00110 {
    00111         return container_of(req, struct aes_block_request, breq);
    00112 }
    00113
    00114 /* Callback called when data read to a buffer list has been decrypted. */
    00115 static void aesblk_buf_list_decrypt_done(struct aes_request *areq,
    00116                 struct slist *buf_list, void *context)
    00117 {
    00118         struct aes_block_request        *abreq = context;
    00119         struct block_request            *breq = &abreq->breq;
    00120         unsigned int iflags;
    00121
    00122         assert(abreq);
    00123
    00124         iflags = cpu_irq_save();
    00125         /* Move the buffers to the requests buffer list. */
    00126         slist_move_to_tail(&breq->buf_list, buf_list);
    00127         aes_free_request(areq);
    00128
    00129         /* Schedule the buffer list complete callback to be called. */
    00130         workqueue_add_item_safe(&main_workqueue, &abreq->worker_item);
    00131         abreq->state |= AES_BLK_STATE_LIST_DECRYPTION_DONE;
    00132
    00133         /* If all buffer lists are processed and a request done is pending,
    00134          * schedule it for completion now. */
    00135         if (--abreq->buf_counter == 0 && (abreq->state
    00136                         & AES_BLK_STATE_DECRYPTION_DONE_PENDING)) {
    00137                 abreq->state &= ~AES_BLK_STATE_DECRYPTION_DONE_PENDING;
    00138                 abreq->state |= AES_BLK_STATE_REQ_DECRYPTION_DONE;
    00139         }
    00140         cpu_irq_restore(iflags);
    00141 }
    00142
    00143 /* Callback called when data has been read from the storage medium to a
    00144  * buffer list. */
    00145 static void aesblk_read_buf_list_done(struct block_device *bdev,
    00146                 struct block_request *breq, struct slist *buf_list)
    00147 {
    00148         struct aes_block_request        *abreq = breq->context;
    00149         struct aes_block_device         *abdev = abreq->abdev;
    00150         struct aes_module               *module = &abdev->module;
    00151         struct aes_request              *areq;
    00152
    00153         /* If the AES module is not in decrypt mode, something is very
    00154          * wrong. */
    00155         assert(aes_get_cipher(module) == AES_DECRYPT);
    00156
    00157         /* In order to keep a request from completing while some buffers are
    00158          * still being processed, we need to count all buffers submitted to
    00159          * the AES module for decryption. */
    00160         abreq->buf_counter++;
    00161
    00162         /* Submit the buffers to the AES module for decryption. */
    00163         areq = aes_alloc_request(module);
    00164         aes_prepare_request(areq, buf_list);
    00165         areq->req_done = aesblk_buf_list_decrypt_done;
    00166         areq->context = abreq;
    00167         aes_submit_request(areq);
    00168 }
    00169
    00170 /* Function called when a buffer list is submitted to an active
    00171  * read request. */
    00172 static int aesblk_submit_read_buf_list(struct block_device *bdev,
    00173                 struct block_request *breq, struct slist *buf_list)
    00174 {
    00175         struct aes_block_request        *abreq = abreq_of(breq);
    00176         struct aes_block_device         *abdev = bdev_to_abdev(bdev);
    00177         struct block_request            *card_breq = abreq->card_breq;
    00178         unsigned int iflags;
    00179
    00180         assert(bdev);
    00181         assert(bdev == breq->bdev);
    00182         assert(breq);
    00183         assert(buf_list);
    00184         assert(!slist_is_empty(buf_list));
    00185
    00186         iflags = cpu_irq_save();
    00187         /* Move the buffers to the block requests buffer list. */
    00188         slist_move_to_tail(&card_breq->buf_list, buf_list);
    00189         cpu_irq_restore(iflags);
    00190
    00191         return block_submit_buf_list(abdev->card_bdev, card_breq,
    00192                         &card_breq->buf_list);
    00193 }
    00194
    00195 /* Callback called when the data read by a read request has been
    00196  * decrypted. */
    00197 static void aesblk_req_decrypt_done(struct aes_request *areq,
    00198                 struct slist *buf_list, void *context)
    00199 {
    00200         struct aes_block_request        *abreq = context;
    00201         struct block_request            *breq = &abreq->breq;
    00202         unsigned int iflags;
    00203
    00204         assert(areq);
    00205
    00206         iflags = cpu_irq_save();
    00207         /* Move the decrypted buffers to the block requests buffer list. */
    00208         if (!slist_is_empty(buf_list))
    00209                 slist_move_to_tail(&breq->buf_list, buf_list);
    00210         aes_free_request(areq);
    00211
    00212         if (abreq->buf_counter > 0) {
    00213                 /* If we still have buffer lists being processed, the
    00214                  * request can not be completed yet. */
    00215                 abreq->state |= AES_BLK_STATE_DECRYPTION_DONE_PENDING;
    00216         } else {
    00217                 /* All buffer lists have been processed, schedule the request
    00218                  * done callback to be called. */
    00219                 workqueue_add_item_safe(&main_workqueue, &abreq->worker_item);
    00220                 abreq->state |= AES_BLK_STATE_REQ_DECRYPTION_DONE;
    00221         }
    00222         cpu_irq_restore(iflags);
    00223 }
    00224
    00225 /* Callback called when data has been read from the storage medium by a
    00226  * read request */
    00227 static void aesblk_req_data_read(struct block_device *bdev,
    00228                 struct block_request *card_breq)
    00229 {
    00230         struct aes_block_request        *abreq = card_breq->context;
    00231         struct aes_module               *module = &abreq->abdev->module;
    00232         struct aes_request              *areq;
    00233
    00234         assert(abreq);
    00235
    00236         /* Submit the read buffers to the AES module for decryption. */
    00237         areq = aes_alloc_request(module);
    00238         aes_prepare_request(areq, &card_breq->buf_list);
    00239         areq->req_done = aesblk_req_decrypt_done;
    00240         areq->context = abreq;
    00241         aes_submit_request(areq);
    00242 }
    00243
    00244 /* Function called when a read request is submitted */
    00245 static void aesblk_submit_read_req(struct block_device *bdev,
    00246                 struct block_request *breq)
    00247 {
    00248         struct aes_block_request        *abreq = abreq_of(breq);
    00249         struct aes_block_device         *abdev = bdev_to_abdev(bdev);
    00250         struct aes_module               *module = &abreq->abdev->module;
    00251         struct block_request            *card_breq = abreq->card_breq;
    00252         unsigned int iflags;
    00253
    00254         iflags = cpu_irq_save();
    00255         /* Move the buffers to the block request used to interface the
    00256          * underlying storage medium. */
    00257         if (!slist_is_empty(&breq->buf_list))
    00258                 slist_move_to_tail(&card_breq->buf_list, &breq->buf_list);
    00259         cpu_irq_restore(iflags);
    00260
    00261         /* Set the AES module to decrypt the stored data. */
    00262         aes_set_cipher(module, AES_DECRYPT);
    00263         /* Start reading from the storage medium. */
    00264         block_submit_req(abdev->card_bdev, card_breq);
    00265 }
    00266
    00267 /* Callback called when the buffer lists submitted to an ongoing write request
    00268  * has been written to the storage medium. */
    00269 static void aesblk_write_buf_list_done(struct block_device *bdev,
    00270                 struct block_request *card_breq, struct slist *buf_list)
    00271 {
    00272         struct aes_block_request        *abreq = card_breq->context;
    00273         struct block_request            *breq = &abreq->breq;
    00274         unsigned int iflags;
    00275
    00276         assert(!slist_is_empty(buf_list));
    00277         /* We are not able to handle errors in the underlying storage medium
    00278          * yet... */
    00279         assert(card_breq->status == -STATUS_IN_PROGRESS);
    00280
    00281         iflags = cpu_irq_save();
    00282         slist_move_to_tail(&breq->buf_list, buf_list);
    00283         workqueue_add_item_safe(&main_workqueue, &abreq->worker_item);
    00284         abreq->state |= AES_BLK_STATE_WRITE_LIST_DONE;
    00285         cpu_irq_restore(iflags);
    00286 }
    00287
    00288 /* Callback called when the buffer lists submitted to an ongoing write request
    00289  * has been encrypted. */
    00290 static void aesblk_buf_list_encrypt_done(struct aes_request *areq,
    00291                 struct slist *buf_list, void *context)
    00292 {
    00293         struct aes_block_request        *abreq = context;
    00294         unsigned int iflags;
    00295
    00296         assert(abreq);
    00297         assert(buf_list);
    00298         assert(!slist_is_empty(buf_list));
    00299         assert(abreq->card_breq->status == -STATUS_IN_PROGRESS);
    00300
    00301         iflags = cpu_irq_save();
    00302         /* Move the encrypted buffers to the requests buffer list. They will
    00303          * later be written to the storage medium. */
    00304         slist_move_to_tail(&abreq->buf_list, buf_list);
    00305         aes_free_request(areq);
    00306
    00307         /* Schedule the encrytped buffers to be written to the storage
    00308          * medium. */
    00309         workqueue_add_item_safe(&main_workqueue, &abreq->worker_item);
    00310         abreq->state |= AES_BLK_STATE_LIST_ENCRYPTION_DONE;
    00311         assert(abreq->buf_counter);
    00312         cpu_irq_restore(iflags);
    00313 }
    00314
    00315 /* Function called when a buffer list is submitted to an ongoing write
    00316  * request. */
    00317 static int aesblk_submit_write_buf_list(struct block_device *bdev,
    00318                 struct block_request *breq, struct slist *buf_list)
    00319 {
    00320         struct aes_block_request        *abreq = abreq_of(breq);
    00321         struct aes_block_device         *abdev = abreq->abdev;
    00322         struct aes_module               *module = &abdev->module;
    00323         struct aes_request              *areq;
    00324
    00325         assert(bdev);
    00326         assert(bdev == breq->bdev);
    00327         assert(abreq);
    00328         assert(buf_list);
    00329         assert(!slist_is_empty(buf_list));
    00330         /* If the AES module is not in encryption mode, something is very
    00331          * wrong. */
    00332         assert(aes_get_cipher(module) == AES_ENCRYPT);
    00333
    00334         /* Submit the buffer list for encryption. */
    00335         areq = aes_alloc_request(&abdev->module);
    00336         aes_prepare_request(areq, buf_list);
    00337         areq->req_done = aesblk_buf_list_encrypt_done;
    00338         areq->context = abreq;
    00339         aes_submit_request(areq);
    00340
    00341         return 0;
    00342 }
    00343
    00344 /* Callback called when the data submitted with a write request has been
    00345  * written to the storage medium. */
    00346 static void aesblk_req_data_written(struct block_device *bdev,
    00347                 struct block_request *card_breq)
    00348 {
    00349         struct aes_block_request        *abreq = card_breq->context;
    00350         struct block_request            *breq = &abreq->breq;
    00351         unsigned int iflags;
    00352
    00353         assert(abreq);
    00354         /* We are not able to handle errors in the underlying storage medium
    00355          * yet... */
    00356         assert(!card_breq->status);
    00357
    00358         iflags = cpu_irq_save();
    00359         /* Move the written buffers to the block requests buffer list and
    00360          * schedule its callback to be called. */
    00361         if (!slist_is_empty(&card_breq->buf_list))
    00362                 slist_move_to_tail(&breq->buf_list, &card_breq->buf_list);
    00363         workqueue_add_item_safe(&main_workqueue, &abreq->worker_item);
    00364         abreq->state |= AES_BLK_STATE_WRITE_REQ_DONE;
    00365         cpu_irq_restore(iflags);
    00366 }
    00367
    00368 /* Callback called when the data submitted with a write request has been
    00369  * encrypted */
    00370 static void aesblk_req_encrypt_done(struct aes_request *areq,
    00371                 struct slist *buf_list, void *context)
    00372 {
    00373         struct aes_block_request *abreq = context;
    00374         unsigned int iflags;
    00375
    00376         assert(abreq);
    00377
    00378         iflags = cpu_irq_save();
    00379         /* Move buffers to the requests buffer list, these will later be
    00380          * written to the storage medium. */
    00381         if (!slist_is_empty(buf_list))
    00382                 slist_move_to_tail(&abreq->buf_list, buf_list);
    00383         aes_free_request(areq);
    00384
    00385         /* Schedule the actual write operation. */
    00386         workqueue_add_item_safe(&main_workqueue, &abreq->worker_item);
    00387         abreq->state |= AES_BLK_STATE_REQ_ENCRYPTION_DONE;
    00388         abreq->buf_counter++;
    00389         cpu_irq_restore(iflags);
    00390 }
    00391
    00392 /* Function called when a write request is submitted */
    00393 static void aesblk_submit_write_req(struct block_device *bdev,
    00394                 struct block_request *breq)
    00395 {
    00396         struct aes_block_request        *abreq = abreq_of(breq);
    00397         struct aes_block_device         *abdev = bdev_to_abdev(bdev);
    00398         struct aes_module               *module = &abdev->module;
    00399         struct aes_request              *aes_req;
    00400
    00401         /* Prepare the AES module and submit the requests buffer list
    00402          * for encryption. */
    00403         aes_set_cipher(module, AES_ENCRYPT);
    00404
    00405         aes_req = aes_alloc_request(module);
    00406         aes_prepare_request(aes_req, &abreq->breq.buf_list);
    00407         aes_req->req_done = aesblk_req_encrypt_done;
    00408         aes_req->context = abreq;
    00409         aes_submit_request(aes_req);
    00410 }
    00411
    00412 /* Worker function called from the workqueue when there is work pending
    00413  * for the AES block device */
    00414 static void aesblk_worker(void *data)
    00415 {
    00416         struct aes_block_request *abreq = data;
    00417         struct aes_block_device *abdev = abreq->abdev;
    00418         struct block_request *breq = &abreq->breq;
    00419         struct block_request *card_breq = abreq->card_breq;
    00420         struct block_device *card_bdev = abdev->card_bdev;
    00421
    00422         cpu_irq_disable();
    00423         if (abreq->state & AES_BLK_STATE_REQ_ENCRYPTION_DONE) {
    00424                 abreq->state &= ~AES_BLK_STATE_REQ_ENCRYPTION_DONE;
    00425                 cpu_irq_enable();
    00426                 block_submit_req(card_bdev, card_breq);
    00427                 cpu_irq_disable();
    00428         }
    00429         if (abreq->state & AES_BLK_STATE_LIST_ENCRYPTION_DONE) {
    00430                 abreq->state &= ~AES_BLK_STATE_LIST_ENCRYPTION_DONE;
    00431                 cpu_irq_enable();
    00432                 assert(abreq->card_breq->status == -STATUS_IN_PROGRESS);
    00433                 block_submit_buf_list(card_bdev, card_breq, &abreq->buf_list);
    00434                 cpu_irq_disable();
    00435         }
    00436         if (abreq->state & AES_BLK_STATE_WRITE_LIST_DONE) {
    00437                 abreq->state &= ~AES_BLK_STATE_WRITE_LIST_DONE;
    00438                 if (breq->buf_list_done) {
    00439                         cpu_irq_enable();
    00440                         breq->buf_list_done(breq->bdev, breq,
    00441                                         &breq->buf_list);
    00442                         cpu_irq_disable();
    00443                 }
    00444         }
    00445         if (abreq->state & AES_BLK_STATE_WRITE_REQ_DONE) {
    00446                 breq->status = card_breq->status;
    00447                 breq->bytes_xfered = card_breq->bytes_xfered;
    00448                 cpu_irq_enable();
    00449                 if (breq->req_done)
    00450                         breq->req_done(&abdev->bdev, &abreq->breq);
    00451                 cpu_irq_disable();
    00452         }
    00453
    00454         if (abreq->state & AES_BLK_STATE_LIST_DECRYPTION_DONE) {
    00455                 abreq->state &= ~AES_BLK_STATE_LIST_DECRYPTION_DONE;
    00456                 cpu_irq_enable();
    00457                 if (breq->buf_list_done)
    00458                         breq->buf_list_done(breq->bdev, breq,
    00459                                         &breq->buf_list);
    00460                 cpu_irq_disable();
    00461         }
    00462         if (abreq->state & AES_BLK_STATE_REQ_DECRYPTION_DONE) {
    00463                 abreq->state &= ~AES_BLK_STATE_REQ_DECRYPTION_DONE;
    00464                 cpu_irq_enable();
    00465                 breq->status = card_breq->status;
    00466                 breq->bytes_xfered = card_breq->bytes_xfered;
    00467                 if (breq->req_done)
    00468                         breq->req_done(&abdev->bdev, breq);
    00469                 cpu_irq_disable();
    00470         }
    00471         cpu_irq_enable();
    00472 }
    00473
    00486 void aesblk_prepare_req(struct block_device *bdev,
    00487                 struct block_request *breq,
    00488                 uint32_t lba, uint32_t nr_blocks,
    00489                 enum block_operation operation)
    00490 {
    00491         struct aes_block_device         *abdev = bdev_to_abdev(bdev);
    00492         struct aes_block_request        *abreq = abreq_of(breq);
    00493         struct block_device             *card_bdev = abdev->card_bdev;
    00494         struct block_request            *card_breq = abreq->card_breq;
    00495
    00496         dbg_verbose("aes prep req %p: LBA %08x blocks %u op %d\n",
    00497                         abreq, lba, nr_blocks, operation);
    00498
    00499         slist_init(&abreq->breq.buf_list);
    00500         breq->status = -STATUS_IN_PROGRESS;
    00501         breq->bytes_xfered = 0;
    00502
    00503         breq->bdev = bdev;
    00504         abreq->abdev = abdev;
    00505         abreq->state = 0;
    00506         abreq->buf_counter = 0;
    00507         slist_init(&abreq->buf_list);
    00508
    00509         workqueue_init_item(&abreq->worker_item, aesblk_worker, abreq);
    00510
    00511         switch (operation) {
    00512         case BLK_OP_READ:
    00513                 block_prepare_req(card_bdev, card_breq,
    00514                                 lba, nr_blocks, operation);
    00515                 breq->req_submit = aesblk_submit_read_req;
    00516                 breq->req_submit_buf_list = aesblk_submit_read_buf_list;
    00517                 card_breq->req_done = aesblk_req_data_read;
    00518                 card_breq->buf_list_done = aesblk_read_buf_list_done;
    00519                 break;
    00520
    00521         case BLK_OP_WRITE:
    00522                 block_prepare_req(card_bdev, card_breq,
    00523                                 lba, nr_blocks, operation);
    00524                 breq->req_submit = aesblk_submit_write_req;
    00525                 breq->req_submit_buf_list = aesblk_submit_write_buf_list;
    00526                 card_breq->req_done = aesblk_req_data_written;
    00527                 card_breq->buf_list_done = aesblk_write_buf_list_done;
    00528                 break;
    00529
    00530         default:
    00531                 unhandled_case(operation);
    00532         }
    00533
    00534         card_breq->context = abreq;
    00535 }
    00536
    00547 struct block_request *aesblk_alloc_req(struct block_device *bdev)
    00548 {
    00549         struct aes_block_request        *abreq;
    00550         struct aes_block_device         *abdev = bdev_to_abdev(bdev);
    00551
    00552         abreq = malloc(sizeof(struct aes_block_request));
    00553         if (unlikely(!abreq))
    00554                 goto err_aes;
    00555
    00556         memset(abreq, 0, sizeof(struct aes_block_request));
    00557         abreq->card_breq = block_alloc_request(abdev->card_bdev);
    00558         if (unlikely(!abreq->card_breq))
    00559                 goto err_card;
    00560
    00561         return &abreq->breq;
    00562
    00563 err_card:
    00564         free(abreq);
    00565 err_aes:
    00566         return NULL;
    00567 }
    00568
    00576 void aesblk_free_req(struct block_device *bdev,
    00577                 struct block_request *breq)
    00578 {
    00579         struct aes_block_request        *abreq = abreq_of(breq);
    00580
    00581         block_free_request(abreq->abdev->card_bdev, abreq->card_breq);
    00582         free(abreq);
    00583 }