/** * genwqe_read_app_id() - Extract app_id * @cd: genwqe device descriptor * @app_name: carrier used to pass-back name * @len: length of data for name * * app_unitcfg need to be filled with valid data first
*/ int genwqe_read_app_id(struct genwqe_dev *cd, char *app_name, int len)
{ int i, j;
u32 app_id = (u32)cd->app_unitcfg;
/** * genwqe_init_crc32() - Prepare a lookup table for fast crc32 calculations * * Existing kernel functions seem to use a different polynom, * therefore we could not use them here. * * Genwqe's Polynomial = 0x20044009
*/ void genwqe_init_crc32(void)
{ int i, j;
u32 crc;
for (i = 0; i < 256; i++) {
crc = i << 24; for (j = 0; j < 8; j++) { if (crc & 0x80000000)
crc = (crc << 1) ^ CRC32_POLYNOMIAL; else
crc = (crc << 1);
}
crc32_tab[i] = crc;
}
}
/** * genwqe_crc32() - Generate 32-bit crc as required for DDCBs * @buff: pointer to data buffer * @len: length of data for calculation * @init: initial crc (0xffffffff at start) * * polynomial = x^32 * + x^29 + x^18 + x^14 + x^3 + 1 (0x20044009) * * Example: 4 bytes 0x01 0x02 0x03 0x04 with init=0xffffffff should * result in a crc32 of 0xf33cb7d3. * * The existing kernel crc functions did not cover this polynom yet. * * Return: crc32 checksum.
*/
u32 genwqe_crc32(u8 *buff, size_t len, u32 init)
{ int i;
u32 crc;
/* * genwqe_alloc_sync_sgl() - Allocate memory for sgl and overlapping pages * * Allocates memory for sgl and overlapping pages. Pages which might * overlap other user-space memory blocks are being cached for DMAs, * such that we do not run into syncronization issues. Data is copied * from user-space into the cached pages.
*/ int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, void __user *user_addr, size_t user_size, int write)
{ int ret = -ENOMEM; struct pci_dev *pci_dev = cd->pci_dev;
p++; /* process next page */ if (p == sgl->nr_pages) goto fixup; /* nothing to do */
}
dma_offs += 128;
s += 8; /* continue 8 elements further */
}
fixup: if (j == 1) { /* combining happened on last entry! */
s -= 8; /* full shift needed on previous sgl block */
j = 7; /* shift all elements */
}
for (i = 0; i < j; i++) /* move elements 1 up */
s[i] = s[i + 1];
/** * genwqe_free_sync_sgl() - Free memory for sgl and overlapping pages * @cd: genwqe device descriptor * @sgl: scatter gather list describing user-space memory * * After the DMA transfer has been completed we free the memory for * the sgl and the cached pages. Data is being transferred from cached * pages into user-space buffers.
*/ int genwqe_free_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl)
{ int rc = 0;
size_t offset; unsignedlong res; struct pci_dev *pci_dev = cd->pci_dev;
/** * genwqe_user_vmap() - Map user-space memory to virtual kernel memory * @cd: pointer to genwqe device * @m: mapping params * @uaddr: user virtual address * @size: size of memory to be mapped * * We need to think about how we could speed this up. Of course it is * not a good idea to do this over and over again, like we are * currently doing it. Nevertheless, I am curious where on the path * the performance is spend. Most probably within the memory * allocation functions, but maybe also in the DMA mapping code. * * Restrictions: The maximum size of the possible mapping currently depends * on the amount of memory we can get using kzalloc() for the * page_list and pci_alloc_consistent for the sg_list. * The sg_list is currently itself not scattered, which could * be fixed with some effort. The page_list must be split into * PAGE_SIZE chunks too. All that will make the complicated * code more complicated. * * Return: 0 if success
*/ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr, unsignedlong size)
{ int rc = -EINVAL; unsignedlong data, offs; struct pci_dev *pci_dev = cd->pci_dev;
if ((uaddr == NULL) || (size == 0)) {
m->size = 0; /* mark unused and not added */ return -EINVAL;
}
m->u_vaddr = uaddr;
m->size = size;
/* determine space needed for page_list. */
data = (unsignedlong)uaddr;
offs = offset_in_page(data); if (size > ULONG_MAX - PAGE_SIZE - offs) {
m->size = 0; /* mark unused and not added */ return -EINVAL;
}
m->nr_pages = DIV_ROUND_UP(offs + size, PAGE_SIZE);
/* * Read-modify-write to preserve the stealth bits * * For SL >= 039, Stealth WE bit allows removing * the read-modify-wrote. * r-m-w may require a mask 0x3C to avoid hitting hard * reset again for error reset (should be 0, chicken).
*/
softrst = __genwqe_readq(cd, IO_SLC_CFGREG_SOFTRESET) & 0x3cull;
__genwqe_writeq(cd, IO_SLC_CFGREG_SOFTRESET, softrst | 0x2ull);
/* give ERRORRESET some time to finish */
msleep(50);
if (genwqe_need_err_masking(cd)) {
dev_info(&pci_dev->dev, "[%s] masking errors for old bitstreams\n", __func__);
__genwqe_writeq(cd, IO_SLC_MISC_DEBUG, 0x0aull);
} return 0;
}
int genwqe_read_softreset(struct genwqe_dev *cd)
{
u64 bitstream;
/** * genwqe_set_interrupt_capability() - Configure MSI capability structure * @cd: pointer to the device * @count: number of vectors to allocate * Return: 0 if no error
*/ int genwqe_set_interrupt_capability(struct genwqe_dev *cd, int count)
{ int rc;
/* fill with invalid data until end */ for (i = idx; i < max_regs; i++) {
regs[i].addr = 0xffffffff;
regs[i].val = 0xffffffffffffffffull;
} return idx;
}
/** * genwqe_ffdc_buff_size() - Calculates the number of dump registers * @cd: genwqe device descriptor * @uid: unit ID
*/ int genwqe_ffdc_buff_size(struct genwqe_dev *cd, int uid)
{ int entries = 0, ring, traps, traces, trace_entries;
u32 eevptr_addr, l_addr, d_len, d_type;
u64 eevptr, val, addr;
if (d_type) { for (i = 0; i < (int)d_len; i++) {
val = __genwqe_readq(cd, d_addr);
set_reg_idx(cd, regs, &idx, max_regs,
d_addr, i, val);
}
} else {
d_len >>= 3; /* Size in bytes! */ for (i = 0; i < (int)d_len; i++, d_addr += 8) {
val = __genwqe_readq(cd, d_addr);
set_reg_idx(cd, regs, &idx, max_regs,
d_addr, 0, val);
}
}
l_addr += 8;
}
}
/* * To save time, there are only 6 traces poplulated on Uid=2, * Ring=1. each with iters=512.
*/ for (ring = 0; ring < 8; ring++) { /* 0 is fls, 1 is fds,
2...7 are ASI rings */
addr = GENWQE_UID_OFFS(uid) | IO_EXTENDED_DIAG_MAP(ring);
val = __genwqe_readq(cd, addr);
if ((val == 0x0ull) || (val == -1ull)) continue;
traps = (val >> 24) & 0xff; /* Number of Traps */
traces = (val >> 16) & 0xff; /* Number of Traces */
trace_entries = val & 0xffff; /* Entries per trace */
/* Note: This is a combined loop that dumps both the traps */ /* (for the trace == 0 case) as well as the traces 1 to */ /* 'traces'. */ for (trace = 0; trace <= traces; trace++) {
u32 diag_sel =
GENWQE_EXTENDED_DIAG_SELECTOR(ring, trace);
/** * genwqe_write_vreg() - Write register in virtual window * @cd: genwqe device descriptor * @reg: register (byte) offset within BAR * @val: value to write * @func: PCI virtual function * * Note, these registers are only accessible to the PF through the * VF-window. It is not intended for the VF to access.
*/ int genwqe_write_vreg(struct genwqe_dev *cd, u32 reg, u64 val, int func)
{
__genwqe_writeq(cd, IO_PF_SLC_VIRTUAL_WINDOW, func & 0xf);
__genwqe_writeq(cd, reg, val); return 0;
}
/** * genwqe_read_vreg() - Read register in virtual window * @cd: genwqe device descriptor * @reg: register (byte) offset within BAR * @func: PCI virtual function * * Note, these registers are only accessible to the PF through the * VF-window. It is not intended for the VF to access.
*/
u64 genwqe_read_vreg(struct genwqe_dev *cd, u32 reg, int func)
{
__genwqe_writeq(cd, IO_PF_SLC_VIRTUAL_WINDOW, func & 0xf); return __genwqe_readq(cd, reg);
}
/** * genwqe_base_clock_frequency() - Deteremine base clock frequency of the card * @cd: genwqe device descriptor * * Note: From a design perspective it turned out to be a bad idea to * use codes here to specifiy the frequency/speed values. An old * driver cannot understand new codes and is therefore always a * problem. Better is to measure out the value or put the * speed/frequency directly into a register which is always a valid * value for old as well as for new software. * * Return: Card clock in MHz
*/ int genwqe_base_clock_frequency(struct genwqe_dev *cd)
{
u16 speed; /* MHz MHz MHz MHz */ staticconstint speed_grade[] = { 250, 200, 166, 175 };
speed = (u16)((cd->slu_unitcfg >> 28) & 0x0full); if (speed >= ARRAY_SIZE(speed_grade)) return 0; /* illegal value */
return speed_grade[speed];
}
/** * genwqe_stop_traps() - Stop traps * @cd: genwqe device descriptor * * Before reading out the analysis data, we need to stop the traps.
*/ void genwqe_stop_traps(struct genwqe_dev *cd)
{
__genwqe_writeq(cd, IO_SLC_MISC_DEBUG_SET, 0xcull);
}
/** * genwqe_start_traps() - Start traps * @cd: genwqe device descriptor * * After having read the data, we can/must enable the traps again.
*/ void genwqe_start_traps(struct genwqe_dev *cd)
{
__genwqe_writeq(cd, IO_SLC_MISC_DEBUG_CLR, 0xcull);
if (genwqe_need_err_masking(cd))
__genwqe_writeq(cd, IO_SLC_MISC_DEBUG, 0x0aull);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.