static int hfi1_vnic_allot_ctxt(struct hfi1_devdata *dd, struct hfi1_ctxtdata **vnic_ctxt) { int rc; rc = allocate_vnic_ctxt(dd, vnic_ctxt); if (rc) { dd_dev_err(dd, "vnic ctxt alloc failed %d\n", rc); return rc; } rc = setup_vnic_ctxt(dd, *vnic_ctxt); if (rc) { dd_dev_err(dd, "vnic ctxt setup failed %d\n", rc); deallocate_vnic_ctxt(dd, *vnic_ctxt); *vnic_ctxt = NULL; } return rc; }
/* * Initialize the EPROM handler. */ int eprom_init(struct hfi1_devdata *dd) { int ret = 0; /* only the discrete chip has an EPROM */ if (dd->pcidev->device != PCI_DEVICE_ID_INTEL0) return 0; /* * It is OK if both HFIs reset the EPROM as long as they don't * do it at the same time. */ ret = acquire_chip_resource(dd, CR_EPROM, EPROM_TIMEOUT); if (ret) { dd_dev_err(dd, "%s: unable to acquire EPROM resource, no EPROM support\n", __func__); goto done_asic; } /* reset EPROM to be sure it is in a good state */ /* set reset */ write_csr(dd, ASIC_EEP_CTL_STAT, ASIC_EEP_CTL_STAT_EP_RESET_SMASK); /* clear reset, set speed */ write_csr(dd, ASIC_EEP_CTL_STAT, EP_SPEED_FULL << ASIC_EEP_CTL_STAT_RATE_SPI_SHIFT); /* wake the device with command "release powerdown NoID" */ write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_RELEASE_POWERDOWN_NOID); dd->eprom_available = true; release_chip_resource(dd, CR_EPROM); done_asic: return ret; }
int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num, struct kobject *kobj) { struct hfi1_pportdata *ppd; struct hfi1_devdata *dd = dd_from_ibdev(ibdev); int ret; if (!port_num || port_num > dd->num_pports) { dd_dev_err(dd, "Skipping infiniband class with invalid port %u\n", port_num); return -ENODEV; } ppd = &dd->pport[port_num - 1]; ret = kobject_init_and_add(&ppd->sc2vl_kobj, &hfi1_sc2vl_ktype, kobj, "sc2vl"); if (ret) { dd_dev_err(dd, "Skipping sc2vl sysfs info, (err %d) port %u\n", ret, port_num); goto bail; } kobject_uevent(&ppd->sc2vl_kobj, KOBJ_ADD); ret = kobject_init_and_add(&ppd->sl2sc_kobj, &hfi1_sl2sc_ktype, kobj, "sl2sc"); if (ret) { dd_dev_err(dd, "Skipping sl2sc sysfs info, (err %d) port %u\n", ret, port_num); goto bail_sc2vl; } kobject_uevent(&ppd->sl2sc_kobj, KOBJ_ADD); ret = kobject_init_and_add(&ppd->vl2mtu_kobj, &hfi1_vl2mtu_ktype, kobj, "vl2mtu"); if (ret) { dd_dev_err(dd, "Skipping vl2mtu sysfs info, (err %d) port %u\n", ret, port_num); goto bail_sl2sc; } kobject_uevent(&ppd->vl2mtu_kobj, KOBJ_ADD); ret = kobject_init_and_add(&ppd->pport_cc_kobj, &port_cc_ktype, kobj, "CCMgtA"); if (ret) { dd_dev_err(dd, "Skipping Congestion Control sysfs info, (err %d) port %u\n", ret, port_num); goto bail_vl2mtu; } kobject_uevent(&ppd->pport_cc_kobj, KOBJ_ADD); ret = sysfs_create_bin_file(&ppd->pport_cc_kobj, &cc_setting_bin_attr); if (ret) { dd_dev_err(dd, "Skipping Congestion Control setting sysfs info, (err %d) port %u\n", ret, port_num); goto bail_cc; } ret = sysfs_create_bin_file(&ppd->pport_cc_kobj, &cc_table_bin_attr); if (ret) { dd_dev_err(dd, "Skipping Congestion Control table sysfs info, (err %d) port %u\n", ret, port_num); goto bail_cc_entry_bin; } dd_dev_info(dd, "Congestion Control Agent enabled for port %d\n", port_num); return 0; bail_cc_entry_bin: sysfs_remove_bin_file(&ppd->pport_cc_kobj, &cc_setting_bin_attr); bail_cc: kobject_put(&ppd->pport_cc_kobj); bail_vl2mtu: kobject_put(&ppd->vl2mtu_kobj); bail_sl2sc: kobject_put(&ppd->sl2sc_kobj); bail_sc2vl: kobject_put(&ppd->sc2vl_kobj); bail: return ret; }
static int allocate_vnic_ctxt(struct hfi1_devdata *dd, struct hfi1_ctxtdata **vnic_ctxt) { struct hfi1_ctxtdata *uctxt; unsigned int ctxt; int ret; if (dd->flags & HFI1_FROZEN) return -EIO; for (ctxt = dd->first_dyn_alloc_ctxt; ctxt < dd->num_rcv_contexts; ctxt++) if (!dd->rcd[ctxt]) break; if (ctxt == dd->num_rcv_contexts) return -EBUSY; uctxt = hfi1_create_ctxtdata(dd->pport, ctxt, dd->node); if (!uctxt) { dd_dev_err(dd, "Unable to create ctxtdata, failing open\n"); return -ENOMEM; } uctxt->flags = HFI1_CAP_KGET(MULTI_PKT_EGR) | HFI1_CAP_KGET(NODROP_RHQ_FULL) | HFI1_CAP_KGET(NODROP_EGR_FULL) | HFI1_CAP_KGET(DMA_RTAIL); uctxt->seq_cnt = 1; /* Allocate and enable a PIO send context */ uctxt->sc = sc_alloc(dd, SC_VNIC, uctxt->rcvhdrqentsize, uctxt->numa_id); ret = uctxt->sc ? 0 : -ENOMEM; if (ret) goto bail; dd_dev_dbg(dd, "allocated vnic send context %u(%u)\n", uctxt->sc->sw_index, uctxt->sc->hw_context); ret = sc_enable(uctxt->sc); if (ret) goto bail; if (dd->num_msix_entries) hfi1_set_vnic_msix_info(uctxt); hfi1_stats.sps_ctxts++; dd_dev_dbg(dd, "created vnic context %d\n", uctxt->ctxt); *vnic_ctxt = uctxt; return ret; bail: /* * hfi1_free_ctxtdata() also releases send_context * structure if uctxt->sc is not null */ dd->rcd[uctxt->ctxt] = NULL; hfi1_free_ctxtdata(dd, uctxt); dd_dev_dbg(dd, "vnic allocation failed. rc %d\n", ret); return ret; }
/* * The segment magic has been checked. There is a footer and table of * contents present. * * directory is a u32 aligned buffer of size EP_PAGE_SIZE. */ static int read_segment_platform_config(struct hfi1_devdata *dd, void *directory, void **data, u32 *size) { struct hfi1_eprom_footer *footer; struct hfi1_eprom_table_entry *table; struct hfi1_eprom_table_entry *entry; void *buffer = NULL; void *table_buffer = NULL; int ret, i; u32 directory_size; u32 seg_base, seg_offset; u32 bytes_available, ncopied, to_copy; /* the footer is at the end of the directory */ footer = (struct hfi1_eprom_footer *) (directory + EP_PAGE_SIZE - sizeof(*footer)); /* make sure the structure version is supported */ if (footer->version != FOOTER_VERSION) return -EINVAL; /* oprom size cannot be larger than a segment */ if (footer->oprom_size >= SEG_SIZE) return -EINVAL; /* the file table must fit in a segment with the oprom */ if (footer->num_table_entries > MAX_TABLE_ENTRIES(SEG_SIZE - footer->oprom_size)) return -EINVAL; /* find the file table start, which precedes the footer */ directory_size = DIRECTORY_SIZE(footer->num_table_entries); if (directory_size <= EP_PAGE_SIZE) { /* the file table fits into the directory buffer handed in */ table = (struct hfi1_eprom_table_entry *) (directory + EP_PAGE_SIZE - directory_size); } else { /* need to allocate and read more */ table_buffer = kmalloc(directory_size, GFP_KERNEL); if (!table_buffer) return -ENOMEM; ret = read_length(dd, SEG_SIZE - directory_size, directory_size, table_buffer); if (ret) goto done; table = table_buffer; } /* look for the platform configuration file in the table */ for (entry = NULL, i = 0; i < footer->num_table_entries; i++) { if (table[i].type == HFI1_EFT_PLATFORM_CONFIG) { entry = &table[i]; break; } } if (!entry) { ret = -ENOENT; goto done; } /* * Sanity check on the configuration file size - it should never * be larger than 4 KiB. */ if (entry->size > (4 * 1024)) { dd_dev_err(dd, "Bad configuration file size 0x%x\n", entry->size); ret = -EINVAL; goto done; } /* check for bogus offset and size that wrap when added together */ if (entry->offset + entry->size < entry->offset) { dd_dev_err(dd, "Bad configuration file start + size 0x%x+0x%x\n", entry->offset, entry->size); ret = -EINVAL; goto done; } /* allocate the buffer to return */ buffer = kmalloc(entry->size, GFP_KERNEL); if (!buffer) { ret = -ENOMEM; goto done; } /* * Extract the file by looping over segments until it is fully read. */ seg_offset = entry->offset % SEG_SIZE; seg_base = entry->offset - seg_offset; ncopied = 0; while (ncopied < entry->size) { /* calculate data bytes available in this segment */ /* start with the bytes from the current offset to the end */ bytes_available = SEG_SIZE - seg_offset; /* subtract off footer and table from segment 0 */ if (seg_base == 0) { /* * Sanity check: should not have a starting point * at or within the directory. */ if (bytes_available <= directory_size) { dd_dev_err(dd, "Bad configuration file - offset 0x%x within footer+table\n", entry->offset); ret = -EINVAL; goto done; } bytes_available -= directory_size; } /* calculate bytes wanted */ to_copy = entry->size - ncopied; /* max out at the available bytes in this segment */ if (to_copy > bytes_available) to_copy = bytes_available; /* * Read from the EPROM. * * The sanity check for entry->offset is done in read_length(). * The EPROM offset is validated against what the hardware * addressing supports. In addition, if the offset is larger * than the actual EPROM, it silently wraps. It will work * fine, though the reader may not get what they expected * from the EPROM. */ ret = read_length(dd, seg_base + seg_offset, to_copy, buffer + ncopied); if (ret) goto done; ncopied += to_copy; /* set up for next segment */ seg_offset = footer->oprom_size; seg_base += SEG_SIZE; } /* success */ ret = 0; *data = buffer; *size = entry->size; done: kfree(table_buffer); if (ret) kfree(buffer); return ret; }