Print this page
MFV: illumos-gate@9a48f6c443e5968307491ba7cc134bbdd0328801
9806 ehci_take_control() can infinite loop due to PCI invalid reads
Reviewed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Jason King <jason.king@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Approved by: Richard Lowe <richlowe@richlowe.net>
Author: Robert Mustacchi <rm@joyent.com>
NEX-16600 "No SOF interrupts have been received" on HPE ProLiant DL380 Gen10, leading to non-working USB EHCI controller
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c
          +++ new/usr/src/uts/common/io/usb/hcd/ehci/ehci_util.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + * Copyright (c) 2018, Joyent, Inc.
  24   25   */
  25   26  
  26   27  /*
       28 + * Copyright 2018 Nexenta Systems, Inc.
       29 + */
       30 +
       31 +/*
  27   32   * EHCI Host Controller Driver (EHCI)
  28   33   *
  29   34   * The EHCI driver is a software driver which interfaces to the Universal
  30   35   * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
  31   36   * the Host Controller is defined by the EHCI Host Controller Interface.
  32   37   *
  33   38   * This module contains the main EHCI driver code which handles all USB
  34   39   * transfers, bandwidth allocations and other general functionalities.
  35   40   */
  36   41  
↓ open down ↓ 701 lines elided ↑ open up ↑
 738  743          if (ehci_is_polled(ehcip->ehci_dip)) {
 739  744                  extern pri_t maxclsyspri;
 740  745  
 741  746                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
 742  747                      "ehci_register_intrs_and_init_mutex: "
 743  748                      "running in simulated polled mode");
 744  749  
 745  750                  (void) thread_create(NULL, 0, ehci_poll_intr, ehcip, 0, &p0,
 746  751                      TS_RUN, maxclsyspri);
 747  752  
 748      -                goto skip_intr;
      753 +                return (DDI_SUCCESS);
 749  754          }
 750  755  
 751  756  #if defined(__x86)
 752  757          /*
 753  758           * Make sure that the interrupt pin is connected to the
 754  759           * interrupt controller on x86.  Interrupt line 255 means
 755  760           * "unknown" or "not connected" (PCI spec 6.2.4, footnote 43).
 756  761           * If we would return failure when interrupt line equals 255, then
 757  762           * high speed devices will be routed to companion host controllers.
 758  763           * However, it is not necessary to return failure here, and
↓ open down ↓ 53 lines elided ↑ open up ↑
 812  817                  }
 813  818  
 814  819                  USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
 815  820                      "ehci_register_intrs_and_init_mutex: "
 816  821                      "Using FIXED interrupt type\n");
 817  822  
 818  823                  ehcip->ehci_intr_type = DDI_INTR_TYPE_FIXED;
 819  824                  ehcip->ehci_flags |= EHCI_INTR;
 820  825          }
 821  826  
 822      -skip_intr:
 823      -        /* Create prototype for advance on async schedule */
 824      -        cv_init(&ehcip->ehci_async_schedule_advance_cv,
 825      -            NULL, CV_DRIVER, NULL);
 826      -
 827  827          return (DDI_SUCCESS);
 828  828  }
 829  829  
 830  830  
 831  831  /*
 832  832   * ehci_add_intrs:
 833  833   *
 834  834   * Register FIXED or MSI interrupts.
 835  835   */
 836  836  static int
 837      -ehci_add_intrs(ehci_state_t     *ehcip,
 838      -                int             intr_type)
      837 +ehci_add_intrs(ehci_state_t *ehcip, int intr_type)
 839  838  {
 840  839          int     actual, avail, intr_size, count = 0;
 841  840          int     i, flag, ret;
 842  841  
 843  842          USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
 844  843              "ehci_add_intrs: interrupt type 0x%x", intr_type);
 845  844  
 846  845          /* Get number of interrupts */
 847  846          ret = ddi_intr_get_nintrs(ehcip->ehci_dip, intr_type, &count);
 848  847          if ((ret != DDI_SUCCESS) || (count == 0)) {
↓ open down ↓ 318 lines elided ↑ open up ↑
1167 1166                          } else if (ehci_vt62x2_workaround) {
1168 1167  
1169 1168                          USB_DPRINTF_L1(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1170 1169                              "Applying VIA workarounds");
1171 1170                  }
1172 1171          }
1173 1172  
1174 1173          return (DDI_SUCCESS);
1175 1174  }
1176 1175  
1177      -
1178 1176  /*
1179      - * ehci_init_check_status
1180      - *
1181      - * Check if EHCI host controller is running
1182      - */
1183      -int
1184      -ehci_init_check_status(ehci_state_t     *ehcip)
1185      -{
1186      -        clock_t                 sof_time_wait;
1187      -
1188      -        /*
1189      -         * Get the number of clock ticks to wait.
1190      -         * This is based on the maximum time it takes for a frame list rollover
1191      -         * and maximum time wait for SOFs to begin.
1192      -         */
1193      -        sof_time_wait = drv_usectohz((EHCI_NUM_PERIODIC_FRAME_LISTS * 1000) +
1194      -            EHCI_SOF_TIMEWAIT);
1195      -
1196      -        /* Tell the ISR to broadcast ehci_async_schedule_advance_cv */
1197      -        ehcip->ehci_flags |= EHCI_CV_INTR;
1198      -
1199      -        /* We need to add a delay to allow the chip time to start running */
1200      -        (void) cv_reltimedwait(&ehcip->ehci_async_schedule_advance_cv,
1201      -            &ehcip->ehci_int_mutex, sof_time_wait, TR_CLOCK_TICK);
1202      -
1203      -        /*
1204      -         * Check EHCI host controller is running, otherwise return failure.
1205      -         */
1206      -        if ((ehcip->ehci_flags & EHCI_CV_INTR) ||
1207      -            (Get_OpReg(ehci_status) & EHCI_STS_HOST_CTRL_HALTED)) {
1208      -
1209      -                USB_DPRINTF_L0(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1210      -                    "No SOF interrupts have been received, this USB EHCI host"
1211      -                    "controller is unusable");
1212      -
1213      -                /*
1214      -                 * Route all Root hub ports to Classic host
1215      -                 * controller, in case this is an unusable ALI M5273
1216      -                 * EHCI controller.
1217      -                 */
1218      -                if (ehcip->ehci_vendor_id == PCI_VENDOR_ALI) {
1219      -                        Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_CLASSIC);
1220      -                }
1221      -
1222      -                return (DDI_FAILURE);
1223      -        }
1224      -
1225      -        return (DDI_SUCCESS);
1226      -}
1227      -
1228      -
1229      -/*
1230 1177   * ehci_init_ctlr:
1231 1178   *
1232 1179   * Initialize the Host Controller (HC).
1233 1180   */
1234 1181  int
1235      -ehci_init_ctlr(ehci_state_t     *ehcip,
1236      -                int             init_type)
     1182 +ehci_init_ctlr(ehci_state_t *ehcip, int init_type)
1237 1183  {
1238 1184          USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl, "ehci_init_ctlr:");
1239 1185  
1240 1186          if (init_type == EHCI_NORMAL_INITIALIZATION) {
1241 1187  
1242 1188                  if (ehci_init_hardware(ehcip) != DDI_SUCCESS) {
1243 1189  
1244 1190                          return (DDI_FAILURE);
1245 1191                  }
1246 1192          }
↓ open down ↓ 70 lines elided ↑ open up ↑
1317 1263          /*
1318 1264           * Set the desired interrupt threshold and turn on EHCI host controller.
1319 1265           */
1320 1266          Set_OpReg(ehci_command,
1321 1267              ((Get_OpReg(ehci_command) & ~EHCI_CMD_INTR_THRESHOLD) |
1322 1268              (EHCI_CMD_01_INTR | EHCI_CMD_HOST_CTRL_RUN)));
1323 1269  
1324 1270          ASSERT(Get_OpReg(ehci_command) & EHCI_CMD_HOST_CTRL_RUN);
1325 1271  
1326 1272          if (init_type == EHCI_NORMAL_INITIALIZATION) {
1327      -
1328 1273                  if (ehci_init_workaround(ehcip) != DDI_SUCCESS) {
1329 1274  
1330 1275                          /* Set host controller soft state to error */
1331 1276                          ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
1332 1277  
1333 1278                          return (DDI_FAILURE);
1334 1279                  }
1335      -
1336      -                if (ehci_init_check_status(ehcip) != DDI_SUCCESS) {
1337      -
1338      -                        /* Set host controller soft state to error */
1339      -                        ehcip->ehci_hc_soft_state = EHCI_CTLR_ERROR_STATE;
1340      -
1341      -                        return (DDI_FAILURE);
1342      -                }
1343      -
1344      -                USB_DPRINTF_L4(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1345      -                    "ehci_init_ctlr: SOF's have started");
1346 1280          }
1347 1281  
1348 1282          /* Route all Root hub ports to EHCI host controller */
1349 1283          Set_OpReg(ehci_config_flag, EHCI_CONFIG_FLAG_EHCI);
1350 1284  
1351 1285          return (DDI_SUCCESS);
1352 1286  }
1353 1287  
1354 1288  /*
1355 1289   * ehci_take_control:
↓ open down ↓ 43 lines elided ↑ open up ↑
1399 1333          /*
1400 1334           * According EHCI Spec 2.1.7, A zero offset indicates the
1401 1335           * end of the extended capability list.
1402 1336           */
1403 1337          while (extended_cap_offset) {
1404 1338  
1405 1339                  /* Get the extended capability value. */
1406 1340                  extended_cap = pci_config_get32(ehcip->ehci_config_handle,
1407 1341                      extended_cap_offset);
1408 1342  
     1343 +                /*
     1344 +                 * It's possible that we'll receive an invalid PCI read here due
     1345 +                 * to something going wrong due to platform firmware. This has
     1346 +                 * been observed in the wild depending on the version of ACPI in
     1347 +                 * use. If this happens, we'll assume that the capability does
     1348 +                 * not exist and that we do not need to take control from the
     1349 +                 * BIOS.
     1350 +                 */
     1351 +                if (extended_cap == PCI_EINVAL32) {
     1352 +                        extended_cap_id = EHCI_EX_CAP_ID_RESERVED;
     1353 +                        break;
     1354 +                }
     1355 +
1409 1356                  /* Get the capability ID */
1410 1357                  extended_cap_id = (extended_cap & EHCI_EX_CAP_ID) >>
1411 1358                      EHCI_EX_CAP_ID_SHIFT;
1412 1359  
1413 1360                  /* Check if the card support legacy */
1414 1361                  if (extended_cap_id == EHCI_EX_CAP_ID_BIOS_HANDOFF) {
1415 1362                          break;
1416 1363                  }
1417 1364  
1418 1365                  /* Get the offset of the next capability */
1419 1366                  extended_cap_offset = (extended_cap & EHCI_EX_CAP_NEXT_PTR) >>
1420 1367                      EHCI_EX_CAP_NEXT_PTR_SHIFT;
     1368 +
1421 1369          }
1422 1370  
1423 1371          /*
1424 1372           * Unable to find legacy support in hardware's extended capability list.
1425 1373           * This means we don't need to worry about BIOS handoff.
1426 1374           */
1427 1375          if (extended_cap_id != EHCI_EX_CAP_ID_BIOS_HANDOFF) {
1428 1376  
1429 1377                  USB_DPRINTF_L3(PRINT_MASK_ATTA, ehcip->ehci_log_hdl,
1430 1378                      "ehci_take_control: Hardware doesn't support legacy");
↓ open down ↓ 493 lines elided ↑ open up ↑
1924 1872  
1925 1873          (void) ehci_isoc_cleanup(ehcip);
1926 1874  
1927 1875          if (ehcip->ehci_pflt_dma_handle) {
1928 1876                  ddi_dma_free_handle(&ehcip->ehci_pflt_dma_handle);
1929 1877          }
1930 1878  
1931 1879          if (flags & EHCI_INTR) {
1932 1880                  /* Destroy the mutex */
1933 1881                  mutex_destroy(&ehcip->ehci_int_mutex);
1934      -
1935      -                /* Destroy the async schedule advance condition variable */
1936      -                cv_destroy(&ehcip->ehci_async_schedule_advance_cv);
1937 1882          }
1938 1883  
1939 1884          /* clean up kstat structs */
1940 1885          ehci_destroy_stats(ehcip);
1941 1886  
1942 1887          /* Free ehci hcdi ops */
1943 1888          if (ehcip->ehci_hcdi_ops) {
1944 1889                  usba_free_hcdi_ops(ehcip->ehci_hcdi_ops);
1945 1890          }
1946 1891  
↓ open down ↓ 1022 lines elided ↑ open up ↑
2969 2914          }
2970 2915  }
2971 2916  
2972 2917  
2973 2918  /*
2974 2919   * ehci_find_periodic_node:
2975 2920   *
2976 2921   * Based on the "real" array leaf node and interval, get the periodic node.
2977 2922   */
2978 2923  static uint_t
2979      -ehci_find_periodic_node(uint_t leaf, int interval) {
     2924 +ehci_find_periodic_node(uint_t leaf, int interval)
     2925 +{
2980 2926          uint_t  lattice_leaf;
2981 2927          uint_t  height = ehci_lattice_height(interval);
2982 2928          uint_t  pnode;
2983 2929          int     i;
2984 2930  
2985 2931          /* Get the leaf number in the lattice */
2986 2932          lattice_leaf = leaf + EHCI_NUM_INTR_QH_LISTS - 1;
2987 2933  
2988 2934          /* Get the node in the lattice based on the height and leaf */
2989 2935          pnode = lattice_leaf;
↓ open down ↓ 1700 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX