177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini/* 277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * Copyright (C) 2012 CERN (www.cern.ch) 377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * Author: Alessandro Rubini <rubini@gnudd.com> 477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * 577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * Released according to the GNU GPL, version 2 or any later version. 677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * 777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * This work is part of the White Rabbit project, a research effort led 877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini * by CERN, the European Institute for Nuclear Research. 977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini */ 1077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini#include <linux/module.h> 1177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini#include <linux/slab.h> 1277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini#include <linux/fmc.h> 1377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini#include <linux/sdb.h> 1477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini#include <linux/err.h> 1577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini#include <linux/fmc-sdb.h> 1677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini#include <asm/byteorder.h> 1777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 1877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic uint32_t __sdb_rd(struct fmc_device *fmc, unsigned long address, 1977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int convert) 2077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 2177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini uint32_t res = fmc_readl(fmc, address); 2277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (convert) 2377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return __be32_to_cpu(res); 2477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return res; 2577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 2677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 2777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic struct sdb_array *__fmc_scan_sdb_tree(struct fmc_device *fmc, 2877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini unsigned long sdb_addr, 2977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini unsigned long reg_base, int level) 3077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 3177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini uint32_t onew; 3277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int i, j, n, convert = 0; 3377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_array *arr, *sub; 3477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 3577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini onew = fmc_readl(fmc, sdb_addr); 3677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (onew == SDB_MAGIC) { 3777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* Uh! If we are little-endian, we must convert */ 3877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (SDB_MAGIC != __be32_to_cpu(SDB_MAGIC)) 3977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini convert = 1; 4077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } else if (onew == __be32_to_cpu(SDB_MAGIC)) { 4177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* ok, don't convert */ 4277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } else { 4377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return ERR_PTR(-ENOENT); 4477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 4577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* So, the magic was there: get the count from offset 4*/ 4677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini onew = __sdb_rd(fmc, sdb_addr + 4, convert); 4777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini n = __be16_to_cpu(*(uint16_t *)&onew); 4877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini arr = kzalloc(sizeof(*arr), GFP_KERNEL); 49e42d50baf43120a78985f13f6e9c8f92fae091c2Dan Carpenter if (!arr) 50e42d50baf43120a78985f13f6e9c8f92fae091c2Dan Carpenter return ERR_PTR(-ENOMEM); 51e42d50baf43120a78985f13f6e9c8f92fae091c2Dan Carpenter arr->record = kzalloc(sizeof(arr->record[0]) * n, GFP_KERNEL); 52e42d50baf43120a78985f13f6e9c8f92fae091c2Dan Carpenter arr->subtree = kzalloc(sizeof(arr->subtree[0]) * n, GFP_KERNEL); 53e42d50baf43120a78985f13f6e9c8f92fae091c2Dan Carpenter if (!arr->record || !arr->subtree) { 5477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini kfree(arr->record); 5577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini kfree(arr->subtree); 5677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini kfree(arr); 5777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return ERR_PTR(-ENOMEM); 5877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 59e42d50baf43120a78985f13f6e9c8f92fae091c2Dan Carpenter 6077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini arr->len = n; 6177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini arr->level = level; 6277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini arr->fmc = fmc; 6377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (i = 0; i < n; i++) { 6477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini union sdb_record *r; 6577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 6677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (j = 0; j < sizeof(arr->record[0]); j += 4) { 6777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini *(uint32_t *)((void *)(arr->record + i) + j) = 6877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __sdb_rd(fmc, sdb_addr + (i * 64) + j, convert); 6977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 7077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini r = &arr->record[i]; 7177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini arr->subtree[i] = ERR_PTR(-ENODEV); 7277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (r->empty.record_type == sdb_type_bridge) { 7377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_component *c = &r->bridge.sdb_component; 7477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini uint64_t subaddr = __be64_to_cpu(r->bridge.sdb_child); 7577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini uint64_t newbase = __be64_to_cpu(c->addr_first); 7677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 7777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini subaddr += reg_base; 7877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini newbase += reg_base; 7977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini sub = __fmc_scan_sdb_tree(fmc, subaddr, newbase, 8077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini level + 1); 8177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini arr->subtree[i] = sub; /* may be error */ 8277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (IS_ERR(sub)) 8377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini continue; 8477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini sub->parent = arr; 8577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini sub->baseaddr = newbase; 8677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 8777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 8877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return arr; 8977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 9077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 9177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubiniint fmc_scan_sdb_tree(struct fmc_device *fmc, unsigned long address) 9277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 9377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_array *ret; 9477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (fmc->sdb) 9577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return -EBUSY; 9677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini ret = __fmc_scan_sdb_tree(fmc, address, 0 /* regs */, 0); 9777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (IS_ERR(ret)) 9877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return PTR_ERR(ret); 9977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc->sdb = ret; 10077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return 0; 10177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 10277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_scan_sdb_tree); 10377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 10477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic void __fmc_sdb_free(struct sdb_array *arr) 10577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 10677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int i, n; 10777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 10877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!arr) 10977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return; 11077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini n = arr->len; 11177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (i = 0; i < n; i++) { 11277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (IS_ERR(arr->subtree[i])) 11377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini continue; 11477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __fmc_sdb_free(arr->subtree[i]); 11577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 11677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini kfree(arr->record); 11777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini kfree(arr->subtree); 11877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini kfree(arr); 11977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 12077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 12177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubiniint fmc_free_sdb_tree(struct fmc_device *fmc) 12277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 12377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __fmc_sdb_free(fmc->sdb); 12477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc->sdb = NULL; 12577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return 0; 12677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 12777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_free_sdb_tree); 12877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 12977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini/* This helper calls reprogram and inizialized sdb as well */ 13077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubiniint fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw, 13177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int sdb_entry) 13277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 13377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int ret; 13477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 13577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini ret = fmc->op->reprogram(fmc, d, gw); 13677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (ret < 0) 13777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return ret; 13877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (sdb_entry < 0) 13977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return ret; 14077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 14177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* We are required to find SDB at a given offset */ 14277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini ret = fmc_scan_sdb_tree(fmc, sdb_entry); 14377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (ret < 0) { 14477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_err(&fmc->dev, "Can't find SDB at address 0x%x\n", 14577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini sdb_entry); 14677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return -ENODEV; 14777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 14877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini fmc_dump_sdb(fmc); 14977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return 0; 15077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 15177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_reprogram); 15277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 1532e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubinistatic char *__strip_trailing_space(char *buf, char *str, int len) 1542e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini{ 1552e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini int i = len - 1; 1562e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini 1572e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini memcpy(buf, str, len); 1582e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini while(i >= 0 && buf[i] == ' ') 1592e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini buf[i--] = '\0'; 1602e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini return buf; 1612e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini} 1622e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini 1632e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini#define __sdb_string(buf, field) ({ \ 1642e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \ 1652e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini __strip_trailing_space(buf, (void *)(field), sizeof(field)); \ 1662e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini }) 1672e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini 16877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic void __fmc_show_sdb_tree(const struct fmc_device *fmc, 16977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini const struct sdb_array *arr) 17077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 17183b1bfba100c1e747c281049255a4a32197c6393Alessandro Rubini unsigned long base = arr->baseaddr; 17277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int i, j, n = arr->len, level = arr->level; 1732e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini char buf[64]; 17477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 17577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (i = 0; i < n; i++) { 17677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini union sdb_record *r; 17777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_product *p; 17877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_component *c; 17977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini r = &arr->record[i]; 18077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini c = &r->dev.sdb_component; 18177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini p = &c->product; 18283b1bfba100c1e747c281049255a4a32197c6393Alessandro Rubini 18377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_info(&fmc->dev, "SDB: "); 18477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 18577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (j = 0; j < level; j++) 18677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT " "); 18777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini switch (r->empty.record_type) { 18877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_interconnect: 18977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "%08llx:%08x %.19s\n", 19077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(p->vendor_id), 19177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be32_to_cpu(p->device_id), 19277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini p->name); 19377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 19477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_device: 19577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "%08llx:%08x %.19s (%08llx-%08llx)\n", 19677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(p->vendor_id), 19777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be32_to_cpu(p->device_id), 19877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini p->name, 19977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(c->addr_first) + base, 20077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(c->addr_last) + base); 20177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 20277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_bridge: 20377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "%08llx:%08x %.19s (bridge: %08llx)\n", 20477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(p->vendor_id), 20577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be32_to_cpu(p->device_id), 20677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini p->name, 20777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(c->addr_first) + base); 20877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (IS_ERR(arr->subtree[i])) { 2092e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini dev_info(&fmc->dev, "SDB: (bridge error %li)\n", 2102e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini PTR_ERR(arr->subtree[i])); 21177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 21277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 21377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __fmc_show_sdb_tree(fmc, arr->subtree[i]); 21477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 21577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_integration: 21677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "integration\n"); 21777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 21877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_repo_url: 2192e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini printk(KERN_CONT "Synthesis repository: %s\n", 2202e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini __sdb_string(buf, r->repo_url.repo_url)); 22177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 22277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_synthesis: 2232e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini printk(KERN_CONT "Bitstream '%s' ", 2242e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini __sdb_string(buf, r->synthesis.syn_name)); 2252e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini printk(KERN_CONT "synthesized %08x by %s ", 2262e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini __be32_to_cpu(r->synthesis.date), 2272e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini __sdb_string(buf, r->synthesis.user_name)); 2282e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini printk(KERN_CONT "(%s version %x), ", 2292e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini __sdb_string(buf, r->synthesis.tool_name), 2302e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini __be32_to_cpu(r->synthesis.tool_version)); 2312e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini printk(KERN_CONT "commit %pm\n", 2322e70efd9afab7a512b6e2e164bf5c25fd3ce6aaeAlessandro Rubini r->synthesis.commit_id); 23377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 23477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_empty: 23577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "empty\n"); 23677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 23777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini default: 23877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "UNKNOWN TYPE 0x%02x\n", 23977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini r->empty.record_type); 24077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 24177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 24277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 24377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 24477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 24577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinivoid fmc_show_sdb_tree(const struct fmc_device *fmc) 24677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 24777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!fmc->sdb) 24877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return; 24977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __fmc_show_sdb_tree(fmc, fmc->sdb); 25077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 25177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_show_sdb_tree); 25277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 25377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinisigned long fmc_find_sdb_device(struct sdb_array *tree, 25477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini uint64_t vid, uint32_t did, unsigned long *sz) 25577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 25677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini signed long res = -ENODEV; 25777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini union sdb_record *r; 25877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_product *p; 25977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_component *c; 26077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int i, n = tree->len; 26177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini uint64_t last, first; 26277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 26377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* FIXME: what if the first interconnect is not at zero? */ 26477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (i = 0; i < n; i++) { 26577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini r = &tree->record[i]; 26677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini c = &r->dev.sdb_component; 26777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini p = &c->product; 26877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 26977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!IS_ERR(tree->subtree[i])) 27077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini res = fmc_find_sdb_device(tree->subtree[i], 27177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini vid, did, sz); 27277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (res >= 0) 27377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return res + tree->baseaddr; 27477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (r->empty.record_type != sdb_type_device) 27577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini continue; 27677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (__be64_to_cpu(p->vendor_id) != vid) 27777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini continue; 27877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (__be32_to_cpu(p->device_id) != did) 27977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini continue; 28077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* found */ 28177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini last = __be64_to_cpu(c->addr_last); 28277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini first = __be64_to_cpu(c->addr_first); 28377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (sz) 28477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini *sz = (typeof(*sz))(last + 1 - first); 28577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return first + tree->baseaddr; 28677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 28777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return res; 28877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 28977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_find_sdb_device); 290