diff options
Diffstat (limited to 'src/vlib/pci/pci.c')
-rw-r--r-- | src/vlib/pci/pci.c | 214 |
1 files changed, 171 insertions, 43 deletions
diff --git a/src/vlib/pci/pci.c b/src/vlib/pci/pci.c index 249a26b1d21..b6a9416cbc3 100644 --- a/src/vlib/pci/pci.c +++ b/src/vlib/pci/pci.c @@ -52,9 +52,25 @@ vlib_pci_main_t pci_main; -vlib_pci_device_info_t * __attribute__ ((weak)) -vlib_pci_get_device_info (vlib_main_t * vm, vlib_pci_addr_t * addr, - clib_error_t ** error) +VLIB_REGISTER_LOG_CLASS (pci_log, static) = { + .class_name = "pci", +}; + +#define log_debug(h, f, ...) \ + vlib_log (VLIB_LOG_LEVEL_DEBUG, pci_log.class, "%U: " f, \ + format_vlib_pci_log, h, ##__VA_ARGS__) + +u8 * +format_vlib_pci_log (u8 *s, va_list *va) +{ + vlib_pci_dev_handle_t h = va_arg (*va, vlib_pci_dev_handle_t); + return format (s, "%U", format_vlib_pci_addr, + vlib_pci_get_addr (vlib_get_main (), h)); +} + +vlib_pci_device_info_t *__attribute__ ((weak)) +vlib_pci_get_device_info (vlib_main_t *vm, vlib_pci_addr_t *addr, + clib_error_t **error) { if (error) *error = clib_error_return (0, "unsupported"); @@ -73,6 +89,122 @@ vlib_pci_addr_t * __attribute__ ((weak)) vlib_pci_get_all_dev_addrs () } static clib_error_t * +_vlib_pci_config_set_control_bit (vlib_main_t *vm, vlib_pci_dev_handle_t h, + u16 bit, int new_val, int *already_set) +{ + u16 control, old; + clib_error_t *err; + + err = vlib_pci_read_write_config ( + vm, h, VLIB_READ, STRUCT_OFFSET_OF (vlib_pci_config_t, command), &old, + STRUCT_SIZE_OF (vlib_pci_config_t, command)); + + if (err) + return err; + + control = new_val ? old | bit : old & ~bit; + *already_set = old == control; + if (*already_set) + return 0; + + return vlib_pci_read_write_config ( + vm, h, VLIB_WRITE, STRUCT_OFFSET_OF (vlib_pci_config_t, command), &control, + STRUCT_SIZE_OF (vlib_pci_config_t, command)); +} + +clib_error_t * +vlib_pci_intr_enable (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + const vlib_pci_config_reg_command_t cmd = { .intx_disable = 1 }; + clib_error_t *err; + int already_set; + + err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 0, &already_set); + log_debug (h, "interrupt%senabled", already_set ? " " : " already "); + return err; +} + +clib_error_t * +vlib_pci_intr_disable (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + const vlib_pci_config_reg_command_t cmd = { .intx_disable = 1 }; + clib_error_t *err; + int already_set; + + err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 1, &already_set); + log_debug (h, "interrupt%sdisabled", already_set ? " " : " already "); + return err; +} + +clib_error_t * +vlib_pci_bus_master_enable (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + const vlib_pci_config_reg_command_t cmd = { .bus_master = 1 }; + clib_error_t *err; + int already_set; + + err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 1, &already_set); + log_debug (h, "bus-master%senabled", already_set ? " " : " already "); + return err; +} + +clib_error_t * +vlib_pci_bus_master_disable (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + const vlib_pci_config_reg_command_t cmd = { .bus_master = 1 }; + clib_error_t *err; + int already_set; + + err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 0, &already_set); + log_debug (h, "bus-master%sdisabled", already_set ? " " : " already "); + return err; +} + +clib_error_t * +vlib_pci_function_level_reset (vlib_main_t *vm, vlib_pci_dev_handle_t h) +{ + vlib_pci_config_t cfg; + pci_capability_pcie_t *cap; + pci_capability_pcie_dev_control_t dev_control; + clib_error_t *err; + u8 offset; + + log_debug (h, "function level reset"); + + err = vlib_pci_read_write_config (vm, h, VLIB_READ, 0, &cfg, sizeof (cfg)); + if (err) + return err; + + offset = cfg.cap_ptr; + + while (offset) + { + cap = (pci_capability_pcie_t *) (cfg.data + offset); + + if (cap->capability_id == PCI_CAP_ID_PCIE) + break; + + offset = cap->next_offset; + } + + if (cap->capability_id != PCI_CAP_ID_PCIE) + return clib_error_return (0, "PCIe capability config not found"); + + if (cap->dev_caps.flr_capable == 0) + return clib_error_return (0, "PCIe function level reset not supported"); + + dev_control = cap->dev_control; + dev_control.function_level_reset = 1; + + if ((err = vlib_pci_write_config_u16 ( + vm, h, offset + STRUCT_OFFSET_OF (pci_capability_pcie_t, dev_control), + &dev_control.as_u16))) + return err; + + return 0; +} + +static clib_error_t * show_pci_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { @@ -151,38 +283,54 @@ format_vlib_pci_addr (u8 * s, va_list * va) u8 * format_vlib_pci_link_port (u8 *s, va_list *va) { - vlib_pci_device_info_t *d = va_arg (*va, vlib_pci_device_info_t *); - pcie_config_regs_t *r = - pci_config_find_capability (&d->config0, PCI_CAP_ID_PCIE); + vlib_pci_config_t *c = va_arg (*va, vlib_pci_config_t *); + pci_capability_pcie_t *r = pci_config_find_capability (c, PCI_CAP_ID_PCIE); + + if (!r) + return format (s, "unknown"); + + return format (s, "P%d", r->link_caps.port_number); +} + +static u8 * +_vlib_pci_link_speed (u8 *s, u8 speed, u8 width) +{ + static char *speeds[] = { + [1] = "2.5", [2] = "5.0", [3] = "8.0", [4] = "16.0", [5] = "32.0" + }; + + if (speed > ARRAY_LEN (speeds) || speeds[speed] == 0) + s = format (s, "unknown speed"); + else + s = format (s, "%s GT/s", speeds[speed]); + + return format (s, " x%u", width); +} + +u8 * +format_vlib_pci_link_speed (u8 *s, va_list *va) +{ + vlib_pci_config_t *c = va_arg (*va, vlib_pci_config_t *); + pci_capability_pcie_t *r = pci_config_find_capability (c, PCI_CAP_ID_PCIE); if (!r) return format (s, "unknown"); - return format (s, "P%d", r->link_capabilities >> 24); + return _vlib_pci_link_speed (s, r->link_status.link_speed, + r->link_status.negotiated_link_width); } u8 * -format_vlib_pci_link_speed (u8 * s, va_list * va) +format_vlib_pci_link_speed_cap (u8 *s, va_list *va) { - vlib_pci_device_info_t *d = va_arg (*va, vlib_pci_device_info_t *); - pcie_config_regs_t *r = - pci_config_find_capability (&d->config0, PCI_CAP_ID_PCIE); - int width; + vlib_pci_config_t *c = va_arg (*va, vlib_pci_config_t *); + pci_capability_pcie_t *r = pci_config_find_capability (c, PCI_CAP_ID_PCIE); if (!r) return format (s, "unknown"); - width = (r->link_status >> 4) & 0x3f; - - if ((r->link_status & 0xf) == 1) - return format (s, "2.5 GT/s x%u", width); - if ((r->link_status & 0xf) == 2) - return format (s, "5.0 GT/s x%u", width); - if ((r->link_status & 0xf) == 3) - return format (s, "8.0 GT/s x%u", width); - if ((r->link_status & 0xf) == 4) - return format (s, "16.0 GT/s x%u", width); - return format (s, "unknown"); + return _vlib_pci_link_speed (s, r->link_caps.max_link_speed, + r->link_caps.max_link_width); } u8 * @@ -257,29 +405,9 @@ format_vlib_pci_vpd (u8 * s, va_list * args) return s; } - -/* *INDENT-OFF* */ VLIB_CLI_COMMAND (show_pci_command, static) = { .path = "show pci", .short_help = "show pci [all]", .function = show_pci_fn, }; -/* *INDENT-ON* */ -clib_error_t * -pci_bus_init (vlib_main_t * vm) -{ - vlib_pci_main_t *pm = &pci_main; - pm->log_default = vlib_log_register_class ("pci", 0); - return 0; -} - -VLIB_INIT_FUNCTION (pci_bus_init); - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ |