fmc-sdb.c revision e42d50baf43120a78985f13f6e9c8f92fae091c2
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 15377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinistatic void __fmc_show_sdb_tree(const struct fmc_device *fmc, 15477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini const struct sdb_array *arr) 15577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 15677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int i, j, n = arr->len, level = arr->level; 15777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini const struct sdb_array *ap; 15877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 15977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (i = 0; i < n; i++) { 16077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini unsigned long base; 16177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini union sdb_record *r; 16277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_product *p; 16377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_component *c; 16477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini r = &arr->record[i]; 16577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini c = &r->dev.sdb_component; 16677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini p = &c->product; 16777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini base = 0; 16877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (ap = arr; ap; ap = ap->parent) 16977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini base += ap->baseaddr; 17077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini dev_info(&fmc->dev, "SDB: "); 17177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 17277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (j = 0; j < level; j++) 17377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT " "); 17477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini switch (r->empty.record_type) { 17577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_interconnect: 17677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "%08llx:%08x %.19s\n", 17777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(p->vendor_id), 17877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be32_to_cpu(p->device_id), 17977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini p->name); 18077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 18177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_device: 18277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "%08llx:%08x %.19s (%08llx-%08llx)\n", 18377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(p->vendor_id), 18477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be32_to_cpu(p->device_id), 18577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini p->name, 18677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(c->addr_first) + base, 18777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(c->addr_last) + base); 18877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 18977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_bridge: 19077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "%08llx:%08x %.19s (bridge: %08llx)\n", 19177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(p->vendor_id), 19277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be32_to_cpu(p->device_id), 19377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini p->name, 19477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __be64_to_cpu(c->addr_first) + base); 19577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (IS_ERR(arr->subtree[i])) { 19677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "(bridge error %li)\n", 19777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini PTR_ERR(arr->subtree[i])); 19877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 19977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 20077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __fmc_show_sdb_tree(fmc, arr->subtree[i]); 20177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 20277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_integration: 20377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "integration\n"); 20477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 20577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_repo_url: 20677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "repo-url\n"); 20777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 20877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_synthesis: 20977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "synthesis-info\n"); 21077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 21177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini case sdb_type_empty: 21277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "empty\n"); 21377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 21477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini default: 21577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini printk(KERN_CONT "UNKNOWN TYPE 0x%02x\n", 21677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini r->empty.record_type); 21777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini break; 21877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 21977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 22077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 22177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 22277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinivoid fmc_show_sdb_tree(const struct fmc_device *fmc) 22377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 22477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!fmc->sdb) 22577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return; 22677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini __fmc_show_sdb_tree(fmc, fmc->sdb); 22777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 22877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_show_sdb_tree); 22977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 23077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubinisigned long fmc_find_sdb_device(struct sdb_array *tree, 23177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini uint64_t vid, uint32_t did, unsigned long *sz) 23277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini{ 23377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini signed long res = -ENODEV; 23477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini union sdb_record *r; 23577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_product *p; 23677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini struct sdb_component *c; 23777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini int i, n = tree->len; 23877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini uint64_t last, first; 23977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 24077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* FIXME: what if the first interconnect is not at zero? */ 24177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini for (i = 0; i < n; i++) { 24277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini r = &tree->record[i]; 24377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini c = &r->dev.sdb_component; 24477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini p = &c->product; 24577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini 24677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (!IS_ERR(tree->subtree[i])) 24777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini res = fmc_find_sdb_device(tree->subtree[i], 24877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini vid, did, sz); 24977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (res >= 0) 25077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return res + tree->baseaddr; 25177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (r->empty.record_type != sdb_type_device) 25277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini continue; 25377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (__be64_to_cpu(p->vendor_id) != vid) 25477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini continue; 25577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (__be32_to_cpu(p->device_id) != did) 25677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini continue; 25777864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini /* found */ 25877864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini last = __be64_to_cpu(c->addr_last); 25977864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini first = __be64_to_cpu(c->addr_first); 26077864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini if (sz) 26177864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini *sz = (typeof(*sz))(last + 1 - first); 26277864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return first + tree->baseaddr; 26377864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini } 26477864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini return res; 26577864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro Rubini} 26677864f2e0a824a92bd93b4c9ad22c31d28ff55a6Alessandro RubiniEXPORT_SYMBOL(fmc_find_sdb_device); 267