Changes in uspace/drv/ehci-hcd/pci.c [0d3167e:0969e45e] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/ehci-hcd/pci.c
r0d3167e r0969e45e 27 27 */ 28 28 /** 29 * @addtogroup drvusb uhci29 * @addtogroup drvusbehci 30 30 * @{ 31 31 */ 32 32 /** 33 33 * @file 34 * PCI related functions needed by the UHCI driver.34 * PCI related functions needed by the EHCI driver. 35 35 */ 36 36 #include <errno.h> … … 48 48 49 49 #define PAGE_SIZE_MASK 0xfffff000 50 51 50 #define HCC_PARAMS_OFFSET 0x8 52 51 #define HCC_PARAMS_EECP_MASK 0xff 53 52 #define HCC_PARAMS_EECP_OFFSET 8 54 55 #define CMD_OFFSET 0x056 #define CONFIGFLAG_OFFSET 0x4057 53 58 54 #define USBCMD_RUN 1 … … 66 62 #define WAIT_STEP 10 67 63 64 68 65 /** Get address of registers and IRQ for given device. 69 66 * 70 67 * @param[in] dev Device asking for the addresses. 71 * @param[out] mem_reg_address Base address of the memoryrange.72 * @param[out] mem_reg_size Size of the memoryrange.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. 73 70 * @param[out] irq_no IRQ assigned to the device. 74 71 * @return Error code. … … 90 87 rc = hw_res_get_resource_list(parent_phone, &hw_resources); 91 88 if (rc != EOK) { 92 async_hangup(parent_phone); 93 return rc; 89 goto leave; 94 90 } 95 91 … … 104 100 for (i = 0; i < hw_resources.count; i++) { 105 101 hw_resource_t *res = &hw_resources.resources[i]; 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; 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; 122 116 } 123 default: 124 break; 117 break; 118 default: 119 break; 125 120 } 126 121 } 127 122 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 { 123 if (!mem_found) { 134 124 rc = ENOENT; 135 } 136 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: 137 139 async_hangup(parent_phone); 140 138 141 return rc; 139 142 } 140 143 /*----------------------------------------------------------------------------*/ 141 /** Calls the PCI driver with a request to enable interrupts142 *143 * @param[in] device Device asking for interrupts144 * @return Error code.145 */146 144 int pci_enable_interrupts(ddf_dev_t *device) 147 145 { 148 int parent_phone = 149 devman_parent_device_connect(device->handle, IPC_FLAG_BLOCKING); 150 if (parent_phone < 0) { 151 return parent_phone; 152 } 146 int parent_phone = devman_parent_device_connect(device->handle, 147 IPC_FLAG_BLOCKING); 153 148 bool enabled = hw_res_enable_interrupt(parent_phone); 154 149 async_hangup(parent_phone); … … 156 151 } 157 152 /*----------------------------------------------------------------------------*/ 158 /** Implements BIOS handoff routine as decribed in EHCI spec159 *160 * @param[in] device Device asking for interrupts161 * @return Error code.162 */163 153 int pci_disable_legacy(ddf_dev_t *device) 164 154 { … … 170 160 } 171 161 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 */ 162 /* read register space BAR */ 181 163 sysarg_t address = 0x10; 182 164 sysarg_t value; 183 165 184 166 int ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 185 167 IPC_M_CONFIG_SPACE_READ_32, address, &value); 186 CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read PCI config space.\n",187 ret);188 168 usb_log_info("Register space BAR at %p:%x.\n", address, value); 189 169 190 /* clear lower byte, it's not part of the BASEaddress */170 /* clear lower byte, it's not part of the address */ 191 171 uintptr_t registers = (value & 0xffffff00); 192 usb_log_info("Mem ory registers BASEaddress:%p.\n", registers);193 194 /* if nothing setup the hc, we don't needto turn it off */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 */ 195 175 if (registers == 0) 196 176 return ENOTSUP; 197 177 198 /* map EHCI registers*/178 /* EHCI registers need 20 bytes*/ 199 179 void *regs = as_get_mappable_page(4096); 200 180 ret = physmem_map((void*)(registers & PAGE_SIZE_MASK), regs, 1, 201 181 AS_AREA_READ | AS_AREA_WRITE); 202 CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to map registers %p:%p.\n", 203 ret, regs, registers); 204 182 if (ret != EOK) { 183 usb_log_error("Failed(%d) to map registers %p:%p.\n", 184 ret, regs, registers); 185 } 205 186 /* calculate value of BASE */ 206 187 registers = (registers & 0xf00) | (uintptr_t)regs; 207 188 208 const uint32_t hcc_params =209 *(uint32_t*)(registers + HCC_PARAMS_OFFSET); 189 uint32_t hcc_params = *(uint32_t*)(registers + HCC_PARAMS_OFFSET); 190 210 191 usb_log_debug("Value of hcc params register: %x.\n", hcc_params); 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; 192 uint32_t eecp = (hcc_params >> HCC_PARAMS_EECP_OFFSET) & HCC_PARAMS_EECP_MASK; 216 193 usb_log_debug("Value of EECP: %x.\n", eecp); 217 194 218 /* Read the second EEC. i.e. Legacy Support and Control register */219 /* TODO: Check capability type here */220 195 ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 221 196 IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGCTLSTS_OFFSET, &value); 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 */ 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 227 203 ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 228 204 IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value); 229 CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret); 205 if (ret != EOK) { 206 usb_log_error("Failed(%d) to read USBLEGSUP.\n", ret); 207 return ret; 208 } 230 209 usb_log_debug2("USBLEGSUP: %x.\n", value); 231 210 232 /* Request control from firmware/BIOS, by writing 1 to highest byte. 233 * (OS Control semaphore)*/ 211 /* request control from firmware/BIOS, by writing 1 to highest byte */ 234 212 ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 235 213 IPC_M_CONFIG_SPACE_WRITE_8, eecp + USBLEGSUP_OFFSET + 3, 1); 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. */ 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 */ 241 221 while ((wait < DEFAULT_WAIT) && (value & USBLEGSUP_BIOS_CONTROL)) { 242 222 async_usleep(WAIT_STEP); 243 223 ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 244 224 IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value); 245 225 wait += WAIT_STEP; 246 226 } 247 227 248 249 228 if ((value & USBLEGSUP_BIOS_CONTROL) != 0) { 250 usb_log_info("BIOS released control after %d usec.\n", wait); 229 usb_log_warning( 230 "BIOS failed to release control after %d usecs, force it.\n", 231 wait); 232 ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 233 IPC_M_CONFIG_SPACE_WRITE_32, eecp + USBLEGSUP_OFFSET, 234 USBLEGSUP_OS_CONTROL); 235 if (ret != EOK) { 236 usb_log_error("Failed(%d) to force OS EHCI control.\n", ret); 237 return ret; 238 } 251 239 } 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); 255 ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 256 IPC_M_CONFIG_SPACE_WRITE_32, eecp + USBLEGSUP_OFFSET, 257 USBLEGSUP_OS_CONTROL); 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. */ 240 usb_log_info("BIOS released control after %d usec.\n", 241 wait); 242 } 243 244 245 /* zero SMI enables in legacy control register */ 265 246 ret = async_req_3_0(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 266 247 IPC_M_CONFIG_SPACE_WRITE_32, eecp + USBLEGCTLSTS_OFFSET, 0); 267 CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) zero USBLEGCTLSTS.\n", ret); 248 if (ret != EOK) { 249 usb_log_error("Failed(%d) zero USBLEGCTLSTS.\n", ret); 250 return ret; 251 } 268 252 usb_log_debug("Zeroed USBLEGCTLSTS register.\n"); 269 253 270 /* Read again Legacy Support and Control register */271 254 ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 272 255 IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGCTLSTS_OFFSET, &value); 273 CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGCTLSTS.\n", ret); 256 if (ret != EOK) { 257 usb_log_error("Failed(%d) to read USBLEGCTLSTS.\n", ret); 258 return ret; 259 } 274 260 usb_log_debug2("USBLEGCTLSTS: %x.\n", value); 275 261 276 /* Read again Legacy Support register */277 262 ret = async_req_2_1(parent_phone, DEV_IFACE_ID(PCI_DEV_IFACE), 278 263 IPC_M_CONFIG_SPACE_READ_32, eecp + USBLEGSUP_OFFSET, &value); 279 CHECK_RET_HANGUP_RETURN(ret, "Failed(%d) to read USBLEGSUP.\n", ret); 264 if (ret != EOK) { 265 usb_log_error("Failed(%d) to read USBLEGSUP.\n", ret); 266 return ret; 267 } 280 268 usb_log_debug2("USBLEGSUP: %x.\n", value); 281 269 … … 284 272 */ 285 273 286 /* Get size of capability registers in memory space.*/274 /* size of capability registers in memory space */ 287 275 uint8_t operation_offset = *(uint8_t*)registers; 288 276 usb_log_debug("USBCMD offset: %d.\n", operation_offset); 289 290 /* Zero USBCMD register. */ 277 /* zero USBCMD register */ 291 278 volatile uint32_t *usbcmd = 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); 279 (uint32_t*)((uint8_t*)registers + operation_offset); 296 280 usb_log_debug("USBCMD value: %x.\n", *usbcmd); 297 281 if (*usbcmd & USBCMD_RUN) { 298 282 *usbcmd = 0; 299 *usbconfigured = 0;300 283 usb_log_info("EHCI turned off.\n"); 301 284 } else { … … 303 286 } 304 287 288 305 289 async_hangup(parent_phone); 306 return ret; 307 #undef CHECK_RET_HANGUP_RETURN 290 291 return ret; 308 292 } 309 293 /*----------------------------------------------------------------------------*/
Note:
See TracChangeset
for help on using the changeset viewer.