/** * genwqe_stop() - Stop card operation * * Recovery notes: * As long as genwqe_thread runs we might access registers during * error data capture. Same is with the genwqe_health_thread. * When genwqe_bus_reset() fails this function might called two times: * first by the genwqe_health_thread() and later by genwqe_remove() to * unbind the device. We must be able to survive that. * * This function must be robust enough to be called twice. */ static int genwqe_stop(struct genwqe_dev *cd) { genwqe_finish_queue(cd); /* no register access */ genwqe_device_remove(cd); /* device removed, procs killed */ genwqe_release_service_layer(cd); /* here genwqe_thread is stopped */ if (genwqe_is_privileged(cd)) { pci_disable_sriov(cd->pci_dev); /* access pci config space */ genwqe_ffdc_buffs_free(cd); } return 0; }
/** * genwqe_probe() - Device initialization * @pdev: PCI device information struct * * Callable for multiple cards. This function is called on bind. * * Return: 0 if succeeded, < 0 when failed */ static int genwqe_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { int err; struct genwqe_dev *cd; genwqe_init_crc32(); cd = genwqe_dev_alloc(); if (IS_ERR(cd)) { dev_err(&pci_dev->dev, "err: could not alloc mem (err=%d)!\n", (int)PTR_ERR(cd)); return PTR_ERR(cd); } dev_set_drvdata(&pci_dev->dev, cd); cd->pci_dev = pci_dev; err = genwqe_pci_setup(cd); if (err < 0) { dev_err(&pci_dev->dev, "err: problems with PCI setup (err=%d)\n", err); goto out_free_dev; } err = genwqe_start(cd); if (err < 0) { dev_err(&pci_dev->dev, "err: cannot start card services! (err=%d)\n", err); goto out_pci_remove; } if (genwqe_is_privileged(cd)) { err = genwqe_health_check_start(cd); if (err < 0) { dev_err(&pci_dev->dev, "err: cannot start health checking! (err=%d)\n", err); goto out_stop_services; } } return 0; out_stop_services: genwqe_stop(cd); out_pci_remove: genwqe_pci_remove(cd); out_free_dev: genwqe_dev_free(cd); return err; }
/** * genwqe_is_visible() - Determine if sysfs attribute should be visible or not * * VFs have restricted mmio capabilities, so not all sysfs entries * are allowed in VFs. */ static umode_t genwqe_is_visible(struct kobject *kobj, struct attribute *attr, int n) { unsigned int j; struct device *dev = container_of(kobj, struct device, kobj); struct genwqe_dev *cd = dev_get_drvdata(dev); umode_t mode = attr->mode; if (genwqe_is_privileged(cd)) return mode; for (j = 0; genwqe_normal_attributes[j] != NULL; j++) if (genwqe_normal_attributes[j] == attr) return mode; return 0; }
static int genwqe_start(struct genwqe_dev *cd) { int err; struct pci_dev *pci_dev = cd->pci_dev; err = genwqe_read_ids(cd); if (err) return err; if (genwqe_is_privileged(cd)) { /* do this after the tweaks. alloc fail is acceptable */ genwqe_ffdc_buffs_alloc(cd); genwqe_stop_traps(cd); /* Collect registers e.g. FIRs, UNITIDs, traces ... */ genwqe_read_ffdc_regs(cd, cd->ffdc[GENWQE_DBG_REGS].regs, cd->ffdc[GENWQE_DBG_REGS].entries, 0); genwqe_ffdc_buff_read(cd, GENWQE_DBG_UNIT0, cd->ffdc[GENWQE_DBG_UNIT0].regs, cd->ffdc[GENWQE_DBG_UNIT0].entries); genwqe_ffdc_buff_read(cd, GENWQE_DBG_UNIT1, cd->ffdc[GENWQE_DBG_UNIT1].regs, cd->ffdc[GENWQE_DBG_UNIT1].entries); genwqe_ffdc_buff_read(cd, GENWQE_DBG_UNIT2, cd->ffdc[GENWQE_DBG_UNIT2].regs, cd->ffdc[GENWQE_DBG_UNIT2].entries); genwqe_start_traps(cd); if (cd->card_state == GENWQE_CARD_FATAL_ERROR) { dev_warn(&pci_dev->dev, "[%s] chip reload/recovery!\n", __func__); /* * Stealth Mode: Reload chip on either hot * reset or PERST. */ cd->softreset = 0x7Cull; __genwqe_writeq(cd, IO_SLC_CFGREG_SOFTRESET, cd->softreset); err = genwqe_bus_reset(cd); if (err != 0) { dev_err(&pci_dev->dev, "[%s] err: bus reset failed!\n", __func__); goto out; } /* * Re-read the IDs because * it could happen that the bitstream load * failed! */ err = genwqe_read_ids(cd); if (err) goto out; } } err = genwqe_setup_service_layer(cd); /* does a reset to the card */ if (err != 0) { dev_err(&pci_dev->dev, "[%s] err: could not setup servicelayer!\n", __func__); err = -ENODEV; goto out; } if (genwqe_is_privileged(cd)) { /* code is running _after_ reset */ genwqe_tweak_hardware(cd); genwqe_setup_pf_jtimer(cd); genwqe_setup_vf_jtimer(cd); } err = genwqe_device_create(cd); if (err < 0) { dev_err(&pci_dev->dev, "err: chdev init failed! (err=%d)\n", err); goto out_release_service_layer; } return 0; out_release_service_layer: genwqe_release_service_layer(cd); out: if (genwqe_is_privileged(cd)) genwqe_ffdc_buffs_free(cd); return -EIO; }