| 1 | /////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 2 | // File       : ioc_driver.c | 
|---|
| 3 | // Date       : 23/05/2013 | 
|---|
| 4 | // Author     : alain greiner | 
|---|
| 5 | // Maintainer : cesar fuguet | 
|---|
| 6 | // Copyright (c) UPMC-LIP6 | 
|---|
| 7 | /////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 8 | // Implementation notes: | 
|---|
| 9 | // 1) In order to share the code, the two _ioc_read() and _ioc_write() functions | 
|---|
| 10 | // call the same _ioc_access() function, and this function call the selected | 
|---|
| 11 | // physical driver (BDV / HBA / SPI / RDK). | 
|---|
| 12 | // 2) The IOMMU is not supported yet, but the method is the following: | 
|---|
| 13 | // A fixed size 2 Mbytes vseg is allocated to the IOC peripheral, in the I/O | 
|---|
| 14 | // virtual space, and the user buffer is dynamically remapped to one single | 
|---|
| 15 | // big page in the IOMMU page table. | 
|---|
| 16 | // The user buffer is unmapped by the _ioc_completed() function when | 
|---|
| 17 | // the transfer is completed. | 
|---|
| 18 | /////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 19 |  | 
|---|
| 20 | #include <giet_config.h> | 
|---|
| 21 | #include <ioc_driver.h> | 
|---|
| 22 | #include <bdv_driver.h> | 
|---|
| 23 | #include <hba_driver.h> | 
|---|
| 24 | #include <sdc_driver.h> | 
|---|
| 25 | #include <rdk_driver.h> | 
|---|
| 26 | #include <utils.h> | 
|---|
| 27 | #include <tty0.h> | 
|---|
| 28 | #include <iob_driver.h> | 
|---|
| 29 | #include <ctx_handler.h> | 
|---|
| 30 | #include <mmc_driver.h> | 
|---|
| 31 | #include <vmem.h> | 
|---|
| 32 |  | 
|---|
| 33 | #if !defined( SEG_IOC_BASE ) | 
|---|
| 34 | # error: You must define SEG_IOC_BASE in the hard_config.h file | 
|---|
| 35 | #endif | 
|---|
| 36 |  | 
|---|
| 37 | #if !defined( USE_IOB ) | 
|---|
| 38 | # error: You must define USE_IOB in the hard_config.h file | 
|---|
| 39 | #endif | 
|---|
| 40 |  | 
|---|
| 41 | #if !defined(GIET_USE_IOMMU) | 
|---|
| 42 | # error: You must define GIET_USE_IOMMU in the giet_config.h file | 
|---|
| 43 | #endif | 
|---|
| 44 |  | 
|---|
| 45 | #if (USE_IOC_BDV + USE_IOC_SPI + USE_IOC_HBA + USE_IOC_RDK) != 1 | 
|---|
| 46 | # error: You must use only one IOC controller type (BDV or SPI or HBA or RDK) | 
|---|
| 47 | #endif | 
|---|
| 48 |  | 
|---|
| 49 | #if USE_IOC_BDV | 
|---|
| 50 | # include <bdv_driver.h> | 
|---|
| 51 | #endif | 
|---|
| 52 |  | 
|---|
| 53 | #if USE_IOC_SPI | 
|---|
| 54 | # include <sdc_driver.h> | 
|---|
| 55 | #endif | 
|---|
| 56 |  | 
|---|
| 57 | #if USE_IOC_HBA | 
|---|
| 58 | # include <hba_driver.h> | 
|---|
| 59 | #endif | 
|---|
| 60 |  | 
|---|
| 61 | #if USE_IOC_RDK | 
|---|
| 62 | # include <rdk_driver.h> | 
|---|
| 63 | #endif | 
|---|
| 64 |  | 
|---|
| 65 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 66 | // IOC global variables | 
|---|
| 67 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 68 |  | 
|---|
| 69 | #define in_unckdata __attribute__((section (".unckdata"))) | 
|---|
| 70 |  | 
|---|
| 71 | in_unckdata volatile unsigned int _ioc_iommu_ix1 = 0; | 
|---|
| 72 | in_unckdata volatile unsigned int _ioc_iommu_npages; | 
|---|
| 73 |  | 
|---|
| 74 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 75 | // This function transfer data between a memory buffer and the block device. | 
|---|
| 76 | // The buffer lentgth is (count*block_size) bytes. | 
|---|
| 77 | // Arguments are: | 
|---|
| 78 | // - to_mem     : from external storage to memory when non 0. | 
|---|
| 79 | // - mode       : BOOT_PA / BOOT_VA / KERNEL / USER | 
|---|
| 80 | // - lba        : first block index on the external storage. | 
|---|
| 81 | // - buf_vaddr  : virtual base address of the memory buffer. | 
|---|
| 82 | // - count      : number of blocks to be transfered. | 
|---|
| 83 | // Returns 0 if success, > 0 if error. | 
|---|
| 84 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 85 | static unsigned int _ioc_access( unsigned int to_mem, | 
|---|
| 86 | unsigned int channel, | 
|---|
| 87 | unsigned int mode, | 
|---|
| 88 | unsigned int lba, | 
|---|
| 89 | unsigned int buf_vaddr, | 
|---|
| 90 | unsigned int count) | 
|---|
| 91 | { | 
|---|
| 92 |  | 
|---|
| 93 | #if GIET_DEBUG_IOC_DRIVER | 
|---|
| 94 | unsigned int procid  = _get_procid(); | 
|---|
| 95 | unsigned int x       = procid >> (Y_WIDTH + P_WIDTH); | 
|---|
| 96 | unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1); | 
|---|
| 97 | unsigned int p       = procid & ((1<<P_WIDTH)-1); | 
|---|
| 98 | _puts("\n[IOC DEBUG] _ioc_access() : P["); | 
|---|
| 99 | _putd( x ); | 
|---|
| 100 | _puts(","); | 
|---|
| 101 | _putd( y ); | 
|---|
| 102 | _puts(","); | 
|---|
| 103 | _putd( p ); | 
|---|
| 104 | _puts("] enters at cycle "); | 
|---|
| 105 | _putd( _get_proctime() ); | 
|---|
| 106 | _puts("\n - channel  = "); | 
|---|
| 107 | _putd( channel ); | 
|---|
| 108 | _puts("\n - mode     = "); | 
|---|
| 109 | _putd( mode ); | 
|---|
| 110 | _puts("\n - vaddr    = "); | 
|---|
| 111 | _putx( buf_vaddr ); | 
|---|
| 112 | _puts("\n - sectors  = "); | 
|---|
| 113 | _putd( count ); | 
|---|
| 114 | _puts("\n - lba      = "); | 
|---|
| 115 | _putx( lba ); | 
|---|
| 116 | _puts("\n"); | 
|---|
| 117 | #endif | 
|---|
| 118 |  | 
|---|
| 119 | unsigned int error;            // return value | 
|---|
| 120 | unsigned int pt_vbase;         // page table vbase address | 
|---|
| 121 | unsigned int ppn;              // user buffer first page PPN | 
|---|
| 122 | unsigned int flags;            // user buffer protection flags | 
|---|
| 123 | paddr_t      buf_paddr;        // user buffer physical address (if no IOMMU), | 
|---|
| 124 |  | 
|---|
| 125 | // check buffer alignment | 
|---|
| 126 | if ((unsigned int) buf_vaddr & 0x3) | 
|---|
| 127 | { | 
|---|
| 128 | _puts("\n[IOC ERROR] in _ioc_access() : buffer not word aligned\n"); | 
|---|
| 129 | _exit(); | 
|---|
| 130 | } | 
|---|
| 131 |  | 
|---|
| 132 | // check channel | 
|---|
| 133 | if ( (USE_IOC_HBA == 0) && (channel > 0) ) | 
|---|
| 134 | { | 
|---|
| 135 | _puts("\n[IOC ERROR] in _ioc_access() : channel must be 0 when HBA not used\n"); | 
|---|
| 136 | _exit(); | 
|---|
| 137 | } | 
|---|
| 138 |  | 
|---|
| 139 | unsigned int length = count << 9;  // count * 512 bytes | 
|---|
| 140 |  | 
|---|
| 141 | // computing memory buffer physical address | 
|---|
| 142 | if ( (mode == IOC_BOOT_MODE) && ((_get_mmu_mode() & 0x4) == 0) ) // identity mapping | 
|---|
| 143 | { | 
|---|
| 144 | buf_paddr = (paddr_t)buf_vaddr; | 
|---|
| 145 | } | 
|---|
| 146 | else                                                    // V2P translation required | 
|---|
| 147 | { | 
|---|
| 148 | // get page table virtual address | 
|---|
| 149 | pt_vbase = _get_context_slot(CTX_PTAB_ID); | 
|---|
| 150 |  | 
|---|
| 151 | // get user buffer first page ppn and flags | 
|---|
| 152 | unsigned int ko = _v2p_translate( (page_table_t*)pt_vbase, | 
|---|
| 153 | buf_vaddr >> 12, | 
|---|
| 154 | &ppn, | 
|---|
| 155 | &flags ); | 
|---|
| 156 | // check access rights | 
|---|
| 157 | if ( ko ) | 
|---|
| 158 | { | 
|---|
| 159 | _puts("\n[IOC ERROR] in _ioc_access() : buffer unmapped\n"); | 
|---|
| 160 | _exit(); | 
|---|
| 161 | } | 
|---|
| 162 |  | 
|---|
| 163 | if ( (mode == IOC_USER_MODE) && ((flags & PTE_U) == 0) ) | 
|---|
| 164 | { | 
|---|
| 165 | _puts("\n[IOC ERROR] in _ioc_access() : buffer not user accessible\n"); | 
|---|
| 166 | _exit(); | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 | if ( ((flags & PTE_W) == 0 ) && to_mem ) | 
|---|
| 170 | { | 
|---|
| 171 | _puts("\n[IOC ERROR] in _ioc_access() : buffer not writable\n"); | 
|---|
| 172 | _exit(); | 
|---|
| 173 | } | 
|---|
| 174 |  | 
|---|
| 175 | buf_paddr = (((paddr_t)ppn) << 12) | (buf_vaddr & 0xFFF); | 
|---|
| 176 | } | 
|---|
| 177 |  | 
|---|
| 178 | // cache coherence for both L1 & L2 caches | 
|---|
| 179 |  | 
|---|
| 180 | if ( to_mem ) // memory write : invalidate data caches | 
|---|
| 181 | { | 
|---|
| 182 | // L1 cache (only if L1 cache coherence not guaranteed by hardware) | 
|---|
| 183 | if ( GIET_NO_HARD_CC ) _dcache_buf_invalidate( buf_vaddr, length ); | 
|---|
| 184 |  | 
|---|
| 185 | // L2 cache (only if we use an IO-Bridge component in architecture)) | 
|---|
| 186 | if ( USE_IOB ) _mmc_inval( buf_paddr, length ); | 
|---|
| 187 | } | 
|---|
| 188 | else         // memory read : update data caches | 
|---|
| 189 | { | 
|---|
| 190 | // L1 cache : nothing to do for L1 write-through | 
|---|
| 191 |  | 
|---|
| 192 | // L2 cache (only if we use an IO-Bridge component in architecture)) | 
|---|
| 193 | if ( USE_IOB ) _mmc_sync( buf_paddr, length ); | 
|---|
| 194 | } | 
|---|
| 195 |  | 
|---|
| 196 | // select the proper physical device | 
|---|
| 197 |  | 
|---|
| 198 | #if   ( USE_IOC_BDV ) | 
|---|
| 199 | if (to_mem) error = _bdv_read ( mode, lba, buf_paddr, count); | 
|---|
| 200 | else        error = _bdv_write( mode, lba, buf_paddr, count); | 
|---|
| 201 | #elif ( USE_IOC_SPI ) | 
|---|
| 202 | if (to_mem) error = _sdc_read (mode, lba, buf_paddr, count); | 
|---|
| 203 | else        error = _sdc_write(mode, lba, buf_paddr, count); | 
|---|
| 204 | #elif ( USE_IOC_HBA ) | 
|---|
| 205 | if (to_mem) error = _hba_read (channel, mode, lba, buf_paddr, count); | 
|---|
| 206 | else        error = _hba_write(channel, mode, lba, buf_paddr, count); | 
|---|
| 207 | #elif ( USE_IOC_RDK ) | 
|---|
| 208 | if (to_mem) error = _rdk_read (lba, buf_vaddr, count); | 
|---|
| 209 | else        error = _rdk_write(lba, buf_vaddr, count); | 
|---|
| 210 | #endif | 
|---|
| 211 |  | 
|---|
| 212 | return error; | 
|---|
| 213 | } // end _ioc_access() | 
|---|
| 214 |  | 
|---|
| 215 | ////////////////////////////////////////////// | 
|---|
| 216 | unsigned int _ioc_init( unsigned int channel ) | 
|---|
| 217 | { | 
|---|
| 218 |  | 
|---|
| 219 | #if   ( USE_IOC_BDV ) | 
|---|
| 220 |  | 
|---|
| 221 | return _bdv_init(); | 
|---|
| 222 |  | 
|---|
| 223 | #elif ( USE_IOC_SPI ) | 
|---|
| 224 |  | 
|---|
| 225 | return _sdc_init(); | 
|---|
| 226 |  | 
|---|
| 227 | #elif ( USE_IOC_HBA ) | 
|---|
| 228 |  | 
|---|
| 229 | return _hba_init( channel ); | 
|---|
| 230 |  | 
|---|
| 231 | #elif ( USE_IOC_RDK ) | 
|---|
| 232 |  | 
|---|
| 233 | return _rdk_init(); | 
|---|
| 234 |  | 
|---|
| 235 | #endif | 
|---|
| 236 |  | 
|---|
| 237 | } | 
|---|
| 238 |  | 
|---|
| 239 | ////////////////////////////////////////////// | 
|---|
| 240 | unsigned int _ioc_read( unsigned int channel, | 
|---|
| 241 | unsigned int mode, | 
|---|
| 242 | unsigned int lba, | 
|---|
| 243 | void*        buffer, | 
|---|
| 244 | unsigned int count) | 
|---|
| 245 | { | 
|---|
| 246 | return _ioc_access( 1,        // read access | 
|---|
| 247 | channel, | 
|---|
| 248 | mode, | 
|---|
| 249 | lba, | 
|---|
| 250 | (unsigned int) buffer, | 
|---|
| 251 | count ); | 
|---|
| 252 | } | 
|---|
| 253 |  | 
|---|
| 254 | ////////////////////////////////////////////// | 
|---|
| 255 | unsigned int _ioc_write( unsigned int channel, | 
|---|
| 256 | unsigned int mode, | 
|---|
| 257 | unsigned int lba, | 
|---|
| 258 | const void*  buffer, | 
|---|
| 259 | unsigned int count ) | 
|---|
| 260 | { | 
|---|
| 261 | return _ioc_access( 0,        // write access | 
|---|
| 262 | channel, | 
|---|
| 263 | mode, | 
|---|
| 264 | lba, | 
|---|
| 265 | (unsigned int) buffer, | 
|---|
| 266 | count ); | 
|---|
| 267 | } | 
|---|
| 268 |  | 
|---|
| 269 | ///////////////////////////////////////////////////// | 
|---|
| 270 | unsigned int _ioc_get_status( unsigned int  channel ) | 
|---|
| 271 | { | 
|---|
| 272 |  | 
|---|
| 273 | #if   ( USE_IOC_BDV ) | 
|---|
| 274 |  | 
|---|
| 275 | return _bdv_get_status( ); | 
|---|
| 276 |  | 
|---|
| 277 | #elif ( USE_IOC_SPI ) | 
|---|
| 278 |  | 
|---|
| 279 | return _sdc_get_status( ); | 
|---|
| 280 |  | 
|---|
| 281 | #elif ( USE_IOC_HBA ) | 
|---|
| 282 |  | 
|---|
| 283 | return _hba_get_status( channel ); | 
|---|
| 284 |  | 
|---|
| 285 | #elif ( USE_IOC_RDK ) | 
|---|
| 286 |  | 
|---|
| 287 | return rdk_get_status(); | 
|---|
| 288 |  | 
|---|
| 289 | #endif | 
|---|
| 290 |  | 
|---|
| 291 | } | 
|---|
| 292 |  | 
|---|
| 293 | ////////////////////////////////// | 
|---|
| 294 | unsigned int _ioc_get_block_size() | 
|---|
| 295 | { | 
|---|
| 296 |  | 
|---|
| 297 | #if   ( USE_IOC_BDV ) | 
|---|
| 298 |  | 
|---|
| 299 | return _bdv_get_block_size(); | 
|---|
| 300 |  | 
|---|
| 301 | #elif ( USE_IOC_SPI ) | 
|---|
| 302 |  | 
|---|
| 303 | return _sdc_get_block_size(); | 
|---|
| 304 |  | 
|---|
| 305 | #elif ( USE_IOC_HBA ) | 
|---|
| 306 |  | 
|---|
| 307 | return _hba_get_block_size(); | 
|---|
| 308 |  | 
|---|
| 309 | #elif ( USE_IOC_RDK ) | 
|---|
| 310 |  | 
|---|
| 311 | return 512; | 
|---|
| 312 |  | 
|---|
| 313 | #endif | 
|---|
| 314 |  | 
|---|
| 315 | } | 
|---|
| 316 |  | 
|---|
| 317 |  | 
|---|
| 318 | // Local Variables: | 
|---|
| 319 | // tab-width: 4 | 
|---|
| 320 | // c-basic-offset: 4 | 
|---|
| 321 | // c-file-offsets:((innamespace . 0)(inline-open . 0)) | 
|---|
| 322 | // indent-tabs-mode: nil | 
|---|
| 323 | // End: | 
|---|
| 324 | // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4 | 
|---|
| 325 |  | 
|---|