blob: 4bb1507c92b19c939adc8c5a1c42f28c91f3871c [file] [log] [blame]
/*
<:copyright-BRCM:2016:DUAL/GPL:standard
Broadcom Proprietary and Confidential.(c) 2016 Broadcom
All Rights Reserved
Unless you and Broadcom execute a separate written software license
agreement governing use of this software, this software is licensed
to you under the terms of the GNU General Public License version 2
(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
with the following added to such license:
As a special exception, the copyright holders of this software give
you permission to link this software with independent modules, and
to copy and distribute the resulting executable under terms of your
choice, provided that you also meet, for each linked independent
module, the terms and conditions of the license of that module.
An independent module is a module which is not derived from this
software. The special exception does not apply to any modifications
of the software.
Not withstanding the above, under no circumstances may you combine
this software in any way with any other Broadcom software provided
under a license other than the GPL, without Broadcom's express prior
written consent.
:>
*/
/*
might use readl or ioread32
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/compiler.h>
#include <linux/pci.h>
#include <linux/pci_regs.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/gfp.h>
#include <linux/interrupt.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#ifdef TX_ENABLE_EVENT_TRACE
#include <linux/ctype.h>
#include <linux/file.h>
#include <linux/fs.h>
#include "bcm_fld_common.h"
#endif
#include <bcmolt_board_selector.h>
#include "bcmolt_llpcie.h"
#define DRV_NAME "maple"
#define DRV_VERSION "1.0.3"
#define BAR_REGS 0
#define BAR_DDR 2
#define BAR_SRAM 4
/*
bar 1 = 8 Mbyte register space
bar 2 = 16 Mbyte DDR space
bar 3 = 64 Kbyte SRAM space
*/
#define MAPLE_REGS_LENGTH 0x00800000
#define MAPLE_DDR_LENGTH 0x01000000
#define MAPLE_SRAM_LENGTH 0x00010000
#ifdef TX_ENABLE_EVENT_TRACE
#define PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_LO 0x064014U
#define PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_HI 0x064018U
#define PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_BASE_LIMIT 0x064074U
#endif
#define PCIE_REVISION_REGISTER_OFFSET 0x6406CU /* PCIE_PCIE_PCIE_0_PCIE_PCIE_0_MISC_REVISION */
#define PCIE_STATUS_REGISTER_OFFSET 0x64068U /* PCIE_PCIE_PCIE_0_PCIE_PCIE_0_MISC_PCIE_STATUS */
#define PCIE_HARD_DEBUG_REGISTER_OFFSET 0x64204U /* PCIE_PCIE_PCIE_0_PCIE_PCIE_0_MISC_HARD_DEBUG */
#define PCIE_INT_STATUS_REGISTER_OFFSET 0x69400U /* PCIE_PCIE_PCIE_0_CPU_INTR1_INTR_STATUS */
#define PCIE_INT_CLEAR_MASK_OFFSET 0x6940CU /* PCIE_PCIE_PCIE_0_CPU_INTR1_INTR_MASK_CLEAR */
#define PCIE_INTR1_STATUS_REGISTER_OFFSET 0x69300U /* Interrupt Status Register */
#define PCIE_MAPLE_VENDOR_ID 0x14E4 /* PCIE_CFG_TYPE0_EP_SUBSYSTEM_ID_VENDOR_ID */
#define PCIE_MAPLE_DEVICE_ID 0x6862
#define PCIE_MAPLE_6863_SKU_DEVICE_ID 0x6863
#define PCIE_MAPLE_EPON_DEVICE_ID 0x5554
#define MAPLE_DRIVER_NAME DRV_NAME " BCM68620 (Maple) PCI driver " DRV_VERSION
struct proc_dir_entry *bcmolt_dir = NULL;
static DEFINE_PCI_DEVICE_TABLE(maple_pci_tbl) =
{ /* vendor_id, device_id, any, any */
{PCI_DEVICE(PCIE_MAPLE_VENDOR_ID, PCIE_MAPLE_DEVICE_ID)},
{PCI_DEVICE(PCIE_MAPLE_VENDOR_ID, PCIE_MAPLE_6863_SKU_DEVICE_ID)},
{PCI_DEVICE(PCIE_MAPLE_VENDOR_ID, PCIE_MAPLE_EPON_DEVICE_ID)},
{0}
};
MODULE_DEVICE_TABLE (pci, maple_pci_tbl);
typedef struct
{
bcm_ll_dev_info device;
spinlock_t lock;
int err_status;
int phylink;
int prev_datalink;
int datalink;
uint32_t deviceid;
unsigned int *traceaddr;
struct pci_dev *pdev;
int enabled;
} maple_device_info;
static int crt_device = 0;
static bcm_ll_pcie_status_change callback;
static bcmos_bool is_initialized = BCMOS_FALSE;
static maple_device_info devices[MAPLE_MAX_DEVICES];
//static irqreturn_t maple_interrupt (int irq, void *dev_instance);
static maple_device_info *get_maple_pci_info(int crt);
static int maple_write(struct file *file,const char *buffer,size_t count, void *data);
static int maple_read(char *page, char **start, off_t off, int count, int *eof, void *data);
/* Map bus/device to device_id */
static int _pcie_bus_devfv_to_devid(int bus, int devfn)
{
const bus_devfn_devid *map;
for (map = bcmolt_board_pci_map_table_get(); map && map->bus > 0; map++)
{
if (map->bus == bus && map->devfn == devfn)
{
return map->device;
}
}
/* Not found - use incremental mapping */
return crt_device;
}
/* procedure used by OS to connect Maple PCI to allocated memory */
static int __devinit maple_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int rc;
volatile unsigned int readval;
maple_device_info *device_info = NULL;
int dev_id;
u32 val;
if (!pdev)
return 1;
dev_info(&pdev->dev,
"Bus = %d Slot = %d Vendor:device = 0x%04x:0x%04x revision = 0x%02x\n",
pdev->bus->number, pdev->devfn,
pdev->vendor, pdev->device, pdev->revision);
if (crt_device == MAPLE_MAX_DEVICES)
{
printk(" Maximum Maple devices already defined (%d)\n", MAPLE_MAX_DEVICES);
return -ENODEV;
}
dev_id = _pcie_bus_devfv_to_devid(pdev->bus->number, pdev->devfn);
++crt_device;
device_info = &devices[dev_id];
memset(device_info, 0, sizeof(maple_device_info));
spin_lock_init(&device_info->lock);
device_info->deviceid = dev_id;
device_info->pdev = pdev;
/* Enable maple device on PCIe bus and fixup BARs.
* Without fixup, module unload/reload crashes with WRX host
* because PCI hotplug doesn't work and after unload/re-load
* linux believes that BARs are already set.
*/
rc = bcm_ll_pcie_dev_enable(dev_id);
if (rc)
{
printk("Error pci_enable_device_mem = %d\n",rc);
goto err_out;
}
rc = pci_request_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM), DRV_NAME);
if (rc)
goto err_out;
pci_set_master(pdev);
pci_save_state(pdev);
device_info->device.soc_regs_base = (unsigned long)pci_ioremap_bar(pdev, BAR_REGS);
device_info->device.soc_sram_base = (unsigned long)pci_ioremap_bar(pdev, BAR_SRAM);
device_info->device.soc_ddr_base = (unsigned long)pci_ioremap_bar(pdev, BAR_DDR);
device_info->device.soc_ddr_length = (uint32_t)pci_resource_len(pdev, BAR_DDR);
device_info->device.irq = pdev->irq;
pci_set_drvdata(pdev, device_info);
//rc = request_irq(device_info->device.irq, maple_interrupt, IRQF_SHARED, "maple-pcie", device_info);
if (!rc && device_info->device.soc_sram_base)
{
device_info->device.irq_connected = 1;
readval = bcm_pci_read32((uint32_t *)(device_info->device.soc_regs_base + PCIE_REVISION_REGISTER_OFFSET));
printk("Card %d version major=%02x minor=%02x\n",device_info->deviceid,
((readval & 0x0000ff00) >> 8),(readval & 0x000000ff));
printk("regs_start = 0x%lx\nddr_start = 0x%lx\nsram_start = 0x%lx\nddr_length = %d\n",
device_info->device.soc_regs_base,device_info->device.soc_ddr_base,
device_info->device.soc_sram_base, (int)device_info->device.soc_ddr_length);
pci_read_config_dword(pdev,PCI_BASE_ADDRESS_0,&val);
printk("BAR REGS = 0x%x\n",(unsigned int)val);
pci_read_config_dword(pdev,PCI_BASE_ADDRESS_2,&val);
printk("BAR DDR = 0x%x\n",(unsigned int)val);
pci_read_config_dword(pdev,PCI_BASE_ADDRESS_4,&val);
printk("BAR SRAM = 0x%x\n",(unsigned int)val);
readval = bcm_pci_read32((uint32_t *)(device_info->device.soc_regs_base + PCIE_STATUS_REGISTER_OFFSET));
device_info->err_status = readval & 0x0000000f;
device_info->phylink = (readval >> 4) & 0x1;
device_info->datalink = (readval >> 5) & 0x1;
device_info->prev_datalink = device_info->datalink;
}
else
goto err_out;
return rc;
err_out:
pci_disable_device (pdev);
memset(device_info, 0, sizeof(*device_info));
--crt_device;
return rc;
}
static void __devexit maple_pci_remove(struct pci_dev *pdev)
{
int i;
maple_device_info *dev = pci_get_drvdata(pdev);
if (!dev)
return;
if (dev->device.irq_connected)
{
//free_irq(dev->device.irq, dev);
dev->device.irq_connected = 0;
}
if (callback)
{
for (i = 0; i < crt_device; i++)
{
if (devices[i].pdev == pdev)
{
callback(i, BCM_LL_PCIE_LINK_DOWN);
break;
}
}
}
pci_disable_device(pdev);
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
dev->device.soc_sram_base = 0;
dev->device.soc_regs_base = 0;
dev->pdev = NULL;
}
static struct pci_driver maple_pci_driver = {
.name = DRV_NAME,
.id_table = maple_pci_tbl,
.probe = maple_pci_probe,
.remove = __devexit_p(maple_pci_remove),
};
static maple_device_info *get_maple_pci_info(int crt)
{
unsigned int readval=0;
maple_device_info *device;
if (crt >= BCMTR_MAX_OLTS)
return NULL;
device = &devices[crt];
if (device->device.soc_regs_base)
{
if (device->enabled)
{
readval = bcm_pci_read32((uint32_t *)(device->device.soc_regs_base + PCIE_STATUS_REGISTER_OFFSET));
device->err_status = readval & 0x0000000f;
device->phylink = (readval >> 4) & 0x1;
device->datalink = (readval >> 5) & 0x1;
}
else
{
device->err_status = 0;
device->phylink = 0;
device->datalink = 0;
}
}
else
device = NULL;
return device;
}
#if 0
static irqreturn_t maple_interrupt (int irq, void *dev_instance)
{
volatile unsigned int value;
maple_device_info *device_info;
unsigned long flags;
int handled = IRQ_NONE;
uint32_t device;
spin_lock_irqsave(&device_info->lock, flags);
value = bcm_pci_read32((uint32_t *)(device_info->device.soc_regs_base + PCIE_INT_STATUS_REGISTER_OFFSET));
if (value)
{
if (device_info->datalink != device_info->prev_datalink)
{
if (device_info->datalink == BCM_LL_PCIE_LINK_UP)
printk("Device=%d : Link is up !!!\n", device);
else
{
printk("Device=%d : Link is down !!!\n", device);
printk("phy status = 0x%x error status = 0x%x\n", device_info->phylink, device_info->err_status);
}
device_info->prev_datalink = device_info->datalink;
if (callback)
callback(device, device_info->datalink);
}
value = bcm_pci_read32((uint32_t *)(device_info->device.soc_regs_base + PCIE_INTR1_STATUS_REGISTER_OFFSET));
if (!value)
handled = IRQ_HANDLED;
}
spin_unlock_irqrestore(&device_info->lock, flags);
return IRQ_RETVAL(handled);
}
#endif
/* Returns BAR register address */
static int _pci_bar_reg_addr(int res)
{
return 0x10 + res*4;
}
static void _pci_update_resource(struct pci_dev *dev, int resno)
{
struct pci_bus_region region;
u16 cmd;
u32 new, check, mask;
int reg;
struct resource *res = dev->resource + resno;
/*
* Ignore resources for unimplemented BARs and unused resource slots
* for 64 bit BARs.
*/
if (!res->flags)
return;
/*
* Ignore non-moveable resources. This might be legacy resources for
* which no functional BAR register exists or another important
* system resource we shouldn't move around.
*/
if (res->flags & IORESOURCE_PCI_FIXED)
return;
pcibios_resource_to_bus(dev, &region, res);
new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
if (res->flags & IORESOURCE_IO)
mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
else
mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
reg = _pci_bar_reg_addr(resno);
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
if ((new ^ check) & mask) {
dev_err(&dev->dev, "BAR %d: error updating (%#08x != %#08x)\n",
resno, new, check);
}
if (res->flags & IORESOURCE_MEM_64) {
new = region.start >> 16 >> 16;
pci_write_config_dword(dev, reg + 4, new);
pci_read_config_dword(dev, reg + 4, &check);
if (check != new) {
dev_err(&dev->dev, "BAR %d: error updating "
"(high %#08x != %#08x)\n", resno, new, check);
}
}
pci_read_config_word(dev, PCI_COMMAND, &cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
res->flags &= ~IORESOURCE_UNSET;
dev_info(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n",
resno, res, (unsigned long long)region.start,
(unsigned long long)region.end);
}
/* Enable PCI access to device */
bcmos_errno bcm_ll_pcie_dev_enable(int dev_id)
{
maple_device_info *device;
int rc;
if (dev_id >= MAPLE_MAX_DEVICES)
return BCM_ERR_PARM;
device = &devices[dev_id];
if (!device->pdev)
return BCM_ERR_IO;
rc = pci_enable_device_mem(device->pdev);
if (rc)
{
printk("Error pci_enable_device_mem for device %d = %d\n", dev_id, rc);\
goto out;
}
/* Refresh devices's PCIe header */
_pci_update_resource(device->pdev, BAR_REGS);
_pci_update_resource(device->pdev, BAR_SRAM);
_pci_update_resource(device->pdev, BAR_DDR);
device->enabled = 1;
out:
return rc ? BCM_ERR_IO : BCM_ERR_OK;
}
/* Disable PCI access to device */
bcmos_errno bcm_ll_pcie_dev_disable(int dev_id)
{
maple_device_info *device;
printk("%s: device %d\n", __FUNCTION__, dev_id);
if (dev_id >= MAPLE_MAX_DEVICES)
return BCM_ERR_PARM;
device = &devices[dev_id];
if (!device->pdev || !device->enabled)
return BCM_ERR_OK;
pci_disable_device(device->pdev);
device->enabled = 0;
return BCM_ERR_OK;
}
bcmos_errno bcm_ll_pcie_init(void)
{
int rc;
if (is_initialized)
return BCM_ERR_OK;
is_initialized = BCMOS_TRUE;
rc = pci_register_driver(&maple_pci_driver);
printk(KERN_INFO "Maple PCI driver registered with PCI subsystem. rc=%d\n", rc);
return rc ? BCM_ERR_INTERNAL : BCM_ERR_OK;
}
void bcm_ll_pcie_cleanup(void)
{
if (!is_initialized)
return;
is_initialized = BCMOS_FALSE;
pci_unregister_driver(&maple_pci_driver);
crt_device = 0;
memset(devices, 0, sizeof(devices));
}
/*******************************************/
/* procedures executed on insmod and rmmod */
/*******************************************/
static int __init bcm_ll_init_module(void)
{
struct proc_dir_entry *bcmolt_file = NULL;
if ((bcmolt_dir = create_proc_entry("bcmolt", S_IFDIR, NULL)) == NULL)
{
printk("Unable to create /proc/bcmolt entry\n");
return -1;
}
if ((bcmolt_file = create_proc_entry("card", S_IFREG | S_IWUSR | S_IRUGO, bcmolt_dir)) == NULL)
{
printk("Unable to create /proc/bcmolt/card entry\n");
remove_proc_entry("bcmolt", bcmolt_dir);
return -1;
}
bcmolt_file->write_proc = (write_proc_t *)maple_write;
bcmolt_file->read_proc = (read_proc_t *)maple_read;
return 0;
}
static void __exit bcm_ll_cleanup_module(void)
{
bcm_ll_pcie_cleanup();
remove_proc_entry("card", bcmolt_dir);
remove_proc_entry("bcmolt", NULL);
printk("Unregister done\n");
}
/*****************************/
/* APIs used by Host drivers */
/*****************************/
bcmos_errno bcm_ll_pcie_status_change_register(bcm_ll_pcie_status_change cb)
{
int i;
maple_device_info *device_info;
callback = cb;
if(callback)
{
for (i = 0; i < crt_device; i++)
{
device_info = get_maple_pci_info(i);
if (device_info)
callback(i, device_info->datalink);
else
callback(i, BCM_LL_PCIE_LINK_DOWN);
}
}
return BCM_ERR_OK;
}
bcmos_errno bcm_ll_pcie_status_change_unregister(void)
{
callback = NULL;
return BCM_ERR_OK;
}
bcmos_errno bcm_ll_pcie_query(uint8_t dev_id, bcm_ll_dev_info *info)
{
maple_device_info *device_info;
if (!info)
return BCM_ERR_PARM;
if (dev_id < MAPLE_MAX_DEVICES)
{
device_info = get_maple_pci_info(dev_id);
if (device_info && device_info->pdev)
{
if (device_info->datalink == BCM_LL_PCIE_LINK_DOWN)
return BCM_ERR_IO;
*info = device_info->device;
return BCM_ERR_OK;
}
return BCM_ERR_IO;
}
return BCM_ERR_RANGE;
}
bcm_ll_pcie_dev bcm_ll_pcie_dev_get(uint8_t dev_id)
{
maple_device_info *device_info;
if (dev_id < crt_device)
{
device_info = get_maple_pci_info(dev_id);
return (device_info ? device_info->pdev : NULL);
}
return NULL;
}
bcmos_errno bcm_ll_pcie_host_reset_enable(uint8_t dev_id, bcmos_bool enabled)
{
uint32_t val;
val = enabled ? 0 : 1;
bcm_pci_write32((uint32_t *)(devices[dev_id].device.soc_regs_base + PCIE_HARD_DEBUG_REGISTER_OFFSET), val);
return BCM_ERR_OK;
}
#ifdef TX_ENABLE_EVENT_TRACE
bcmos_errno bcm_ll_pcie_setrace(uint8_t dev_id)
{
maple_device_info *device_info;
uint32_t val,lim,base,size;
uint32_t reglo,reghi,baselim;
unsigned long addr;
if (dev_id < crt_device)
{
device_info = &devices[dev_id];
if (!device_info)
return BCM_ERR_IO;
size = EVENT_BUFFER_SIZE;
device_info->traceaddr = (unsigned int *)bcmos_alloc_not_cache(size);
memset(device_info->traceaddr,0,size);
addr = bcmos_virt_to_phys(device_info->traceaddr); /* | 0x02 = reverse byte order = swap */
printk("trace window : alloc=0x%lx size=0x%x\n",(unsigned long)device_info->traceaddr, (unsigned int)size);
reglo = PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_LO;
reghi = PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_HI;
baselim = PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_BASE_LIMIT;
bcm_pci_write32((uint32_t *)(device_info->device.soc_regs_base + reglo),addr & 0xffffffff);
bcm_pci_write32((uint32_t *)(device_info->device.soc_regs_base + reghi)),((addr >> 32) & 0xffffffff);
/* base */
base = CPU_2_PCIE_MEM_WIN1_BASE;
/* limit */
lim = base + size;
val = lim | (base >> 16);
bcm_pci_write32((uint32_t *)(device_info->device.soc_regs_base + baselim),val);
//bcm_fld_set_event_trace(dev_id);
bcm_pci_write32((uint32_t *)(device_info->device.soc_sram_base + BCM_FLD_EVENT_TRACE_OFFSET),0x1);
return BCM_ERR_OK;
}
return BCM_ERR_RANGE;
}
bcmos_errno bcm_ll_pcie_cleartrace(uint8_t dev_id)
{
maple_device_info *device_info;
if (dev_id < crt_device)
{
device_info = &devices[dev_id];
if (!device_info)
return BCM_ERR_IO;
//bcm_fld_clear_event_trace(dev_id);
bcm_pci_write32((uint32_t *)(device_info->device.soc_sram_base + BCM_FLD_EVENT_TRACE_OFFSET),0x0);
return BCM_ERR_OK;
}
return BCM_ERR_RANGE;
}
bcmos_errno bcm_ll_pcie_savetrace(uint8_t dev_id, char *tracefilename)
{
maple_device_info *device_info;
struct file *fp;
unsigned long seg = 0;
mm_segment_t memseg;
if (!tracefilename)
return BCM_ERR_PARM;
printk("device=%d from=%d, Go to write to file %s\n",dev_id , crt_device, tracefilename);
if (dev_id < crt_device)
{
device_info = &devices[dev_id];
if (!device_info)
{
printk("Error: device_info is null\n");
goto exit;
}
fp = filp_open(tracefilename, O_WRONLY | O_CREAT, 0666);
if ((fp == NULL) || (fp == (void *)-ENOENT))
{
printk("Error: Can't open file %s\n",tracefilename);
goto exit;
}
// Get current segment descriptor
seg = get_fs().seg;
// Set segment descriptor associated to kernel space
set_fs(get_ds());
fp->f_op->write(fp, (char *)device_info->traceaddr,EVENT_BUFFER_SIZE, &fp->f_pos);
memseg.seg = seg;
set_fs(memseg);
filp_close(fp, NULL);
printk("Wrote file %s\n",tracefilename);
exit:
bcmos_free_not_cache(device_info->traceaddr);
return BCM_ERR_OK;
}
return BCM_ERR_RANGE;
}
#endif
/*************************************************************/
/* User interface functions : implement echo/cat to proc file*/
/*************************************************************/
typedef struct
{
char *name;
void (*callback)(int cmdid, char *cmd);
char *description;
} maple_card_command;
static char *find_command(char *cmd);
static void command_reg(int cmdid, char *line);
static void command_mem(int cmdid, char *line);
static void command_cfg(int cmdid, char *line);
#ifdef TX_ENABLE_EVENT_TRACE
static void command_trace(int cmdid, char *line);
#endif
#define READCMD 0
#define WRITECMD 1
static maple_card_command commands[] =
{
{"readreg", command_reg, "read register <index> <register offset - hex>"},
{"writereg", command_reg, "write register <index> <register offset - hex> <value - hex>"},
{"read", command_mem, "read <address - hex> <number of words - dec>"},
{"write", command_mem, "write <address - hex> <value - hex>"},
{"rcfg", command_cfg, "read dev <address - hex> <number of words - dec>"},
{"wcfg", command_cfg, "write dev <address - hex> <value - hex>"},
#ifdef TX_ENABLE_EVENT_TRACE
{"trace", command_trace, "trace <index> on/off/save tx trace"},
#endif
{NULL, NULL, NULL}
};
static char *find_command(char *cmd)
{
char *rest;
int i = 0;
maple_card_command *cmdptr = &commands[0];
cmd = skip_spaces(cmd);
if (!strncmp(cmd,"help",strlen("help")))
{
while (cmdptr->name)
{
printk("%s\t: %s\n",cmdptr->name, cmdptr->description);
cmdptr = &commands[++i];
}
return NULL;
}
while (cmdptr->name)
{
if (!strncmp(cmdptr->name, cmd, strlen(cmdptr->name)))
{
rest = cmd + strlen(cmdptr->name);
rest = skip_spaces(rest);
cmdptr->callback(i%2, rest);
return NULL;
}
cmdptr = &commands[++i];
}
return "Wrong command name";
}
/**********************************************************************
answers to cat /proc/bcmolt command
**********************************************************************/
static int maple_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int i;
int len;
maple_device_info *dev = NULL;
len = sprintf(page, "Maple Device Info\n\n");
for (i = 0; i < MAPLE_MAX_DEVICES; i++)
{
dev = get_maple_pci_info(i);
if (dev)
{
len += sprintf(page + len, "id=%d regs_start=0x%lx ddr_start=0x%lx sram_start=0x%lx ddr_length=%d\n",
dev->deviceid,
dev->device.soc_regs_base,dev->device.soc_ddr_base,
dev->device.soc_sram_base, (int)dev->device.soc_ddr_length);
len += sprintf(page + len, "Phy Link is %s Data Link is %s Error status = %d\n\n",
dev->phylink == 1 ? "UP" : "DOWN", dev->datalink == 1 ? "UP" : "DOWN", (int)dev->err_status);
}
}
return len;
}
#ifdef TX_ENABLE_EVENT_TRACE
static void command_trace(int cmdid, char *line)
{
char token[5];
int index;
if (sscanf(line, "%d %s", &index, token) != 2)
{
printk("Wrong parameter\n");
return;
}
printk("TRACE commands : %s\n",token);
if (!strncmp(token,"on",2))
{
//on
bcm_ll_pcie_setrace(index);
return;
}
if (!strncmp(token,"off",3))
{
// off
bcm_ll_pcie_cleartrace(index);
return;
}
if (!strncmp(token,"save",4))
{
//get
char filename[20];
sprintf(filename,"./tt_trace_%d.trx",index);
bcm_ll_pcie_savetrace(index,filename);
return;
}
printk("Wrong command\n");
}
#endif
static void command_reg(int cmdindex, char *line)
{
char *rest;
char *token;
int index;
unsigned long address;
unsigned int reg;
if (sscanf(line, "%d %lx", &index, &address) != 2)
{
printk("Wrong parameter\n");
return;
}
address += (unsigned long)devices[index].device.soc_regs_base;
switch (cmdindex)
{
case READCMD:
reg = bcm_pci_read32((uint32_t *)address);
printk("0x%lx : %08x\n", address, reg);
break;
case WRITECMD:
rest = line;
token = strsep(&rest, " "); /* skip index */
token = strsep(&rest, " "); /* skip address */
token = strsep(&rest, " ");
if (!token)
{
printk("Wrong parameter\n");
return;
}
sscanf(token, "%x", &reg);
printk("write 0x%x to 0x%lx\n", reg, address);
bcm_pci_write32((uint32_t *)address,reg);
break;
}
}
static void command_mem(int cmdindex, char *line)
{
char *token;
char *rest;
unsigned long address;
unsigned int reg;
int i, number_of_words;
int in_line=0, max_in_line;
if (sscanf(line, "%lx", &address) != 1)
{
printk("Wrong parameter\n");
return;
}
rest = line;
token = strsep(&rest, " "); /* skip address */
switch (cmdindex)
{
case READCMD:
token = strsep(&rest, " ");
if (!token)
number_of_words = 1;
else
sscanf(token, "%d", &number_of_words);
max_in_line = 4;
for (i = 0; i < number_of_words; i++, address += 4)
{
if (!in_line)
printk("%08lx: ", address);
reg = bcm_pci_read32((uint32_t *)address);
printk("%08x", reg);
if (++in_line < max_in_line)
printk(" ");
else
{
printk("\n");
in_line = 0;
}
}
if (in_line)
printk("\n");
break;
case WRITECMD:
token = strsep(&rest, " ");
if (!token)
{
printk("Wrong parameter\n");
return;
}
sscanf(token, "%x", &reg);
bcm_pci_write32((uint32_t *)address,reg);
break;
}
}
static void command_cfg(int cmdindex, char *line)
{
unsigned long address;
unsigned int reg;
unsigned int val_or_num;
int crt;
int i;
int in_line=0, max_in_line;
maple_device_info *device;
if (sscanf(line, "%d %lx %x", &crt, &address, &val_or_num) != 3)
{
printk("Wrong parameter\n");
return;
}
if (crt >= crt_device || !devices[crt].pdev)
{
printk("Invalid device %d\n", crt);
return;
}
device = &devices[crt];
switch (cmdindex)
{
case READCMD:
max_in_line = 4;
for (i = 0; i < val_or_num; i++, address += 4)
{
if (!in_line)
printk("%08lx: ", address);
pci_read_config_dword(device->pdev, address, &reg);
printk("%08x", reg);
if (++in_line < max_in_line)
printk(" ");
else
{
printk("\n");
in_line = 0;
}
}
if (in_line)
printk("\n");
break;
case WRITECMD:
pci_write_config_dword(device->pdev, address, val_or_num);
break;
}
}
/**********************************************************************
answers to echo [...] > /proc/bcmolt command
**********************************************************************/
static int maple_write(struct file *file,const char *buffer,size_t count, void *data)
{
char *internal;
if (buffer == NULL)
return -EFAULT;
internal = kmalloc(count, GFP_KERNEL);
if (!internal)
{
printk("Not enough memmory\n");
return count;
}
memset(internal, 0, count);
if (copy_from_user(internal, buffer, count))
{
printk("Not enough memmory\n");
goto error;
}
find_command(internal);
error:
kfree(internal);
return count;
}
EXPORT_SYMBOL(bcmolt_dir);
EXPORT_SYMBOL(bcm_ll_pcie_init);
EXPORT_SYMBOL(bcm_ll_pcie_cleanup);
EXPORT_SYMBOL(bcm_ll_pcie_status_change_register);
EXPORT_SYMBOL(bcm_ll_pcie_status_change_unregister);
EXPORT_SYMBOL(bcm_ll_pcie_query);
EXPORT_SYMBOL(bcm_ll_pcie_dev_get);
EXPORT_SYMBOL(bcm_ll_pcie_dev_enable);
EXPORT_SYMBOL(bcm_ll_pcie_dev_disable);
EXPORT_SYMBOL(bcm_ll_pcie_host_reset_enable);
#ifdef TX_ENABLE_EVENT_TRACE
EXPORT_SYMBOL(bcm_ll_pcie_setrace);
EXPORT_SYMBOL(bcm_ll_pcie_cleartrace);
EXPORT_SYMBOL(bcm_ll_pcie_savetrace);
#endif
module_init(bcm_ll_init_module);
module_exit(bcm_ll_cleanup_module);
MODULE_DESCRIPTION("maple line card");
MODULE_LICENSE("Dual BSD/GPL");