Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/drv/ehci-hcd/pci.c

    r0969e45e r0d3167e  
    2727 */
    2828/**
    29  * @addtogroup drvusbehci
     29 * @addtogroup drvusbuhci
    3030 * @{
    3131 */
    3232/**
    3333 * @file
    34  * PCI related functions needed by the EHCI driver.
     34 * PCI related functions needed by the UHCI driver.
    3535 */
    3636#include <errno.h>
     
    4848
    4949#define PAGE_SIZE_MASK 0xfffff000
     50
    5051#define HCC_PARAMS_OFFSET 0x8
    5152#define HCC_PARAMS_EECP_MASK 0xff
    5253#define HCC_PARAMS_EECP_OFFSET 8
     54
     55#define CMD_OFFSET 0x0
     56#define CONFIGFLAG_OFFSET 0x40
    5357
    5458#define USBCMD_RUN 1
     
    6266#define WAIT_STEP 10
    6367
    64 
    6568/** Get address of registers and IRQ for given device.
    6669 *
    6770 * @param[in] dev Device asking for the addresses.
    68  * @param[out] io_reg_address Base address of the I/O range.
    69  * @param[out] io_reg_size Size of the I/O range.
     71 * @param[out] mem_reg_address Base address of the memory range.
     72 * @param[out] mem_reg_size Size of the memory range.
    7073 * @param[out] irq_no IRQ assigned to the device.
    7174 * @return Error code.
     
    8790        rc = hw_res_get_resource_list(parent_phone, &hw_resources);
    8891        if (rc != EOK) {
    89                 goto leave;
     92                async_hangup(parent_phone);
     93                return rc;
    9094        }
    9195
     
    100104        for (i = 0; i < hw_resources.count; i++) {
    101105                hw_resource_t *res = &hw_resources.resources[i];
    102                 switch (res->type) {
    103                         case INTERRUPT:
    104                                 irq = res->res.interrupt.irq;
    105                                 irq_found = true;
    106                                 usb_log_debug2("Found interrupt: %d.\n", irq);
    107                                 break;
    108                         case MEM_RANGE:
    109                                 if (res->res.mem_range.address != 0
    110                                     && res->res.mem_range.size != 0 ) {
    111                                         mem_address = res->res.mem_range.address;
    112                                         mem_size = res->res.mem_range.size;
    113                                         usb_log_debug2("Found mem: %llx %zu.\n",
    114                                                         res->res.mem_range.address, res->res.mem_range.size);
    115                                         mem_found = true;
     106                switch (res->type)
     107                {
     108                case INTERRUPT:
     109                        irq = res->res.interrupt.irq;
     110                        irq_found = true;
     111                        usb_log_debug2("Found interrupt: %d.\n", irq);
     112                        break;
     113
     114                case MEM_RANGE:
     115                        if (res->res.mem_range.address != 0
     116                            && res->res.mem_range.size != 0 ) {
     117                                mem_address = res->res.mem_range.address;
     118                                mem_size = res->res.mem_range.size;
     119                                usb_log_debug2("Found mem: %llx %zu.\n",
     120                                    mem_address, mem_size);
     121                                mem_found = true;
    116122                                }
    117                                 break;
    118                         default:
    119                                 break;
     123                default:
     124                        break;
    120125                }
    121126        }
    122127
    123         if (!mem_found) {
     128        if (mem_found && irq_found) {
     129                *mem_reg_address = mem_address;
     130                *mem_reg_size = mem_size;
     131                *irq_no = irq;
     132                rc = EOK;
     133        } else {
    124134                rc = ENOENT;
    125                 goto leave;
    126         }
    127 
    128         if (!irq_found) {
    129                 rc = ENOENT;
    130                 goto leave;
    131         }
    132 
    133         *mem_reg_address = mem_address;
    134         *mem_reg_size = mem_size;
    135         *irq_no = irq;
    136 
    137         rc = EOK;
    138 leave:
     135        }
     136
    139137        async_hangup(parent_phone);
    140 
    141138        return rc;
    142139}
    143140/*----------------------------------------------------------------------------*/
     141/** Calls the PCI driver with a request to enable interrupts
     142 *
     143 * @param[in] device Device asking for interrupts
     144 * @return Error code.
     145 */
    144146int pci_enable_interrupts(ddf_dev_t *device)
    145147{
    146         int parent_phone = devman_parent_device_connect(device->handle,
    147             IPC_FLAG_BLOCKING);
     148        int parent_phone =
     149            devman_parent_device_connect(device->handle, IPC_FLAG_BLOCKING);
     150        if (parent_phone < 0) {
     151                return parent_phone;
     152        }
    148153        bool enabled = hw_res_enable_interrupt(parent_phone);
    149154        async_hangup(parent_phone);
     
    151156}
    152157/*----------------------------------------------------------------------------*/
     158/** Implements BIOS handoff routine as decribed in EHCI spec
     159 *
     160 * @param[in] device Device asking for interrupts
     161 * @return Error code.
     162 */
    153163int pci_disable_legacy(ddf_dev_t *device)
    154164{
     
    160170        }
    161171
    162         /* read register space BAR */
     172#define CHECK_RET_HANGUP_RETURN(ret, message...) \
     173        if (ret != EOK) { \
     174                usb_log_error(message); \
     175                async_hangup(parent_phone); \
     176                return ret; \
     177        } else (void)0
     178
     179
     180        /* read register space BASE BAR */
    163181        sysarg_t address = 0x10;
    164182        sysarg_t value;
    165183
    166   int ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
     184        int ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    167185            IPC_M_CONFIG_SPACE_READ_32, address, &value);
     186        CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read PCI config space.\n",
     187            ret);
    168188        usb_log_info("Register space BAR at %p:%x.\n", address, value);
    169189
    170         /* clear lower byte, it's not part of the address */
     190        /* clear lower byte, it's not part of the BASE address */
    171191        uintptr_t registers = (value & 0xffffff00);
    172         usb_log_info("Mem register address:%p.\n", registers);
    173 
    174         /* if nothing setup the hc, the we don't need to to turn it off */
     192        usb_log_info("Memory registers BASE address:%p.\n", registers);
     193
     194        /* if nothing setup the hc, we don't need to turn it off */
    175195        if (registers == 0)
    176196                return ENOTSUP;
    177197
    178         /* EHCI registers need 20 bytes*/
     198        /* map EHCI registers */
    179199        void *regs = as_get_mappable_page(4096);
    180200        ret = physmem_map((void*)(registers & PAGE_SIZE_MASK), regs, 1,
    181201            AS_AREA_READ | AS_AREA_WRITE);
    182         if (ret != EOK) {
    183                 usb_log_error("Failed(%d) to map registers %p:%p.\n",
    184                     ret, regs, registers);
    185         }
     202        CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to map registers %p:%p.\n",
     203            ret, regs, registers);
     204
    186205        /* calculate value of BASE */
    187206        registers = (registers & 0xf00) | (uintptr_t)regs;
    188207
    189         uint32_t hcc_params = *(uint32_t*)(registers + HCC_PARAMS_OFFSET);
    190 
     208        const uint32_t hcc_params =
     209            *(uint32_t*)(registers + HCC_PARAMS_OFFSET);
    191210        usb_log_debug("Value of hcc params register: %x.\n", hcc_params);
    192         uint32_t eecp = (hcc_params >> HCC_PARAMS_EECP_OFFSET) & HCC_PARAMS_EECP_MASK;
     211
     212        /* Read value of EHCI Extended Capabilities Pointer
     213         * (points to PCI config space) */
     214        uint32_t eecp =
     215            (hcc_params >> HCC_PARAMS_EECP_OFFSET) & HCC_PARAMS_EECP_MASK;
    193216        usb_log_debug("Value of EECP: %x.\n", eecp);
    194217
     218        /* Read the second EEC. i.e. Legacy Support and Control register */
     219        /* TODO: Check capability type here */
    195220        ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    196221            IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGCTLSTS_OFFSET, &value);
    197         if (ret != EOK) {
    198                 usb_log_error("Failed(%d) to read USBLEGCTLSTS.\n", ret);
    199                 return ret;
    200         }
    201         usb_log_debug2("USBLEGCTLSTS: %x.\n", value);
    202 
     222        CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGCTLSTS.\n", ret);
     223        usb_log_debug("USBLEGCTLSTS: %x.\n", value);
     224
     225        /* Read the first EEC. i.e. Legacy Support register */
     226        /* TODO: Check capability type here */
    203227        ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    204228            IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value);
    205         if (ret != EOK) {
    206                 usb_log_error("Failed(%d) to read USBLEGSUP.\n", ret);
    207                 return ret;
    208         }
     229        CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret);
    209230        usb_log_debug2("USBLEGSUP: %x.\n", value);
    210231
    211         /* request control from firmware/BIOS, by writing 1 to highest byte */
     232        /* Request control from firmware/BIOS, by writing 1 to highest byte.
     233         * (OS Control semaphore)*/
    212234        ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    213235           IPC_M_CONFIG_SPACE_WRITE_8, eecp + USBLEGSUP_OFFSET + 3, 1);
    214         if (ret != EOK) {
    215                 usb_log_error("Failed(%d) request OS EHCI control.\n", ret);
    216                 return ret;
    217         }
    218 
    219         size_t wait = 0; /* might be anything */
    220         /* wait for BIOS to release control */
     236        CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to request OS EHCI control.\n",
     237            ret);
     238
     239        size_t wait = 0;
     240        /* Wait for BIOS to release control. */
    221241        while ((wait < DEFAULT_WAIT) && (value & USBLEGSUP_BIOS_CONTROL)) {
    222242                async_usleep(WAIT_STEP);
    223243                ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    224                                 IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value);
     244                    IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value);
    225245                wait += WAIT_STEP;
    226246        }
    227247
     248
    228249        if ((value & USBLEGSUP_BIOS_CONTROL) != 0) {
    229                 usb_log_warning(
    230                     "BIOS failed to release control after %d usecs, force it.\n",
    231                     wait);
     250                usb_log_info("BIOS released control after %d usec.\n", wait);
     251        } else {
     252                /* BIOS failed to hand over control, this should not happen. */
     253                usb_log_warning( "BIOS failed to release control after"
     254                    "%d usecs, force it.\n", wait);
    232255                ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    233                           IPC_M_CONFIG_SPACE_WRITE_32, eecp + USBLEGSUP_OFFSET,
     256                    IPC_M_CONFIG_SPACE_WRITE_32, eecp + USBLEGSUP_OFFSET,
    234257                    USBLEGSUP_OS_CONTROL);
    235                 if (ret != EOK) {
    236                         usb_log_error("Failed(%d) to force OS EHCI control.\n", ret);
    237                         return ret;
    238                 }
    239         } else {
    240                 usb_log_info("BIOS released control after %d usec.\n",
    241                     wait);
    242         }
    243 
    244 
    245         /* zero SMI enables in legacy control register */
     258                CHECK_RET_HANGUP_RETURN(ret,
     259                    "Failed(%d) to force OS EHCI control.\n", ret);
     260                /* TODO: This does not seem to work on my machine */
     261        }
     262
     263        /* Zero SMI enables in legacy control register.
     264         * It would prevent pre-OS code from interfering. */
    246265        ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    247266           IPC_M_CONFIG_SPACE_WRITE_32, eecp + USBLEGCTLSTS_OFFSET, 0);
    248         if (ret != EOK) {
    249                 usb_log_error("Failed(%d) zero USBLEGCTLSTS.\n", ret);
    250                 return ret;
    251         }
     267        CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) zero USBLEGCTLSTS.\n", ret);
    252268        usb_log_debug("Zeroed USBLEGCTLSTS register.\n");
    253269
     270        /* Read again Legacy Support and Control register */
    254271        ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    255272            IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGCTLSTS_OFFSET, &value);
    256         if (ret != EOK) {
    257                 usb_log_error("Failed(%d) to read USBLEGCTLSTS.\n", ret);
    258                 return ret;
    259         }
     273        CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGCTLSTS.\n", ret);
    260274        usb_log_debug2("USBLEGCTLSTS: %x.\n", value);
    261275
     276        /* Read again Legacy Support register */
    262277        ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE),
    263278            IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value);
    264         if (ret != EOK) {
    265                 usb_log_error("Failed(%d) to read USBLEGSUP.\n", ret);
    266                 return ret;
    267         }
     279        CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret);
    268280        usb_log_debug2("USBLEGSUP: %x.\n", value);
    269281
     
    272284 */
    273285
    274         /* size of capability registers in memory space */
     286        /* Get size of capability registers in memory space. */
    275287        uint8_t operation_offset = *(uint8_t*)registers;
    276288        usb_log_debug("USBCMD offset: %d.\n", operation_offset);
    277         /* zero USBCMD register */
     289
     290        /* Zero USBCMD register. */
    278291        volatile uint32_t *usbcmd =
    279          (uint32_t*)((uint8_t*)registers + operation_offset);
     292            (uint32_t*)((uint8_t*)registers + operation_offset + CMD_OFFSET);
     293        volatile uint32_t *usbconfigured =
     294            (uint32_t*)((uint8_t*)registers + operation_offset
     295            + CONFIGFLAG_OFFSET);
    280296        usb_log_debug("USBCMD value: %x.\n", *usbcmd);
    281297        if (*usbcmd & USBCMD_RUN) {
    282298                *usbcmd = 0;
     299                *usbconfigured = 0;
    283300                usb_log_info("EHCI turned off.\n");
    284301        } else {
     
    286303        }
    287304
    288 
    289305        async_hangup(parent_phone);
    290 
    291   return ret;
     306        return ret;
     307#undef CHECK_RET_HANGUP_RETURN
    292308}
    293309/*----------------------------------------------------------------------------*/
Note: See TracChangeset for help on using the changeset viewer.