blob: 4bb1507c92b19c939adc8c5a1c42f28c91f3871c [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2<:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written consent.
26
27:>
28 */
29
30/*
31 might use readl or ioread32
32*/
33#include <linux/module.h>
34#include <linux/kernel.h>
35#include <linux/compiler.h>
36#include <linux/pci.h>
37#include <linux/pci_regs.h>
38#include <linux/init.h>
39#include <linux/errno.h>
40#include <linux/string.h>
41#include <linux/proc_fs.h>
42#include <linux/delay.h>
43#include <linux/io.h>
44#include <linux/uaccess.h>
45#include <linux/gfp.h>
46#include <linux/interrupt.h>
47#include <linux/types.h>
48#include <linux/spinlock.h>
49
50#ifdef TX_ENABLE_EVENT_TRACE
51#include <linux/ctype.h>
52#include <linux/file.h>
53#include <linux/fs.h>
54#include "bcm_fld_common.h"
55#endif
56#include <bcmolt_board_selector.h>
57#include "bcmolt_llpcie.h"
58
59#define DRV_NAME "maple"
60#define DRV_VERSION "1.0.3"
61
62#define BAR_REGS 0
63#define BAR_DDR 2
64#define BAR_SRAM 4
65/*
66bar 1 = 8 Mbyte register space
67bar 2 = 16 Mbyte DDR space
68bar 3 = 64 Kbyte SRAM space
69*/
70#define MAPLE_REGS_LENGTH 0x00800000
71#define MAPLE_DDR_LENGTH 0x01000000
72#define MAPLE_SRAM_LENGTH 0x00010000
73
74#ifdef TX_ENABLE_EVENT_TRACE
75#define PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_LO 0x064014U
76#define PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_HI 0x064018U
77#define PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_BASE_LIMIT 0x064074U
78#endif
79#define PCIE_REVISION_REGISTER_OFFSET 0x6406CU /* PCIE_PCIE_PCIE_0_PCIE_PCIE_0_MISC_REVISION */
80#define PCIE_STATUS_REGISTER_OFFSET 0x64068U /* PCIE_PCIE_PCIE_0_PCIE_PCIE_0_MISC_PCIE_STATUS */
81#define PCIE_HARD_DEBUG_REGISTER_OFFSET 0x64204U /* PCIE_PCIE_PCIE_0_PCIE_PCIE_0_MISC_HARD_DEBUG */
82#define PCIE_INT_STATUS_REGISTER_OFFSET 0x69400U /* PCIE_PCIE_PCIE_0_CPU_INTR1_INTR_STATUS */
83#define PCIE_INT_CLEAR_MASK_OFFSET 0x6940CU /* PCIE_PCIE_PCIE_0_CPU_INTR1_INTR_MASK_CLEAR */
84#define PCIE_INTR1_STATUS_REGISTER_OFFSET 0x69300U /* Interrupt Status Register */
85
86#define PCIE_MAPLE_VENDOR_ID 0x14E4 /* PCIE_CFG_TYPE0_EP_SUBSYSTEM_ID_VENDOR_ID */
87#define PCIE_MAPLE_DEVICE_ID 0x6862
88#define PCIE_MAPLE_6863_SKU_DEVICE_ID 0x6863
89#define PCIE_MAPLE_EPON_DEVICE_ID 0x5554
90
91#define MAPLE_DRIVER_NAME DRV_NAME " BCM68620 (Maple) PCI driver " DRV_VERSION
92
93struct proc_dir_entry *bcmolt_dir = NULL;
94static DEFINE_PCI_DEVICE_TABLE(maple_pci_tbl) =
95{ /* vendor_id, device_id, any, any */
96 {PCI_DEVICE(PCIE_MAPLE_VENDOR_ID, PCIE_MAPLE_DEVICE_ID)},
97 {PCI_DEVICE(PCIE_MAPLE_VENDOR_ID, PCIE_MAPLE_6863_SKU_DEVICE_ID)},
98 {PCI_DEVICE(PCIE_MAPLE_VENDOR_ID, PCIE_MAPLE_EPON_DEVICE_ID)},
99 {0}
100};
101MODULE_DEVICE_TABLE (pci, maple_pci_tbl);
102
103typedef struct
104{
105 bcm_ll_dev_info device;
106 spinlock_t lock;
107 int err_status;
108 int phylink;
109 int prev_datalink;
110 int datalink;
111 uint32_t deviceid;
112 unsigned int *traceaddr;
113 struct pci_dev *pdev;
114 int enabled;
115} maple_device_info;
116
117static int crt_device = 0;
118static bcm_ll_pcie_status_change callback;
119static bcmos_bool is_initialized = BCMOS_FALSE;
120
121static maple_device_info devices[MAPLE_MAX_DEVICES];
122//static irqreturn_t maple_interrupt (int irq, void *dev_instance);
123static maple_device_info *get_maple_pci_info(int crt);
124
125static int maple_write(struct file *file,const char *buffer,size_t count, void *data);
126static int maple_read(char *page, char **start, off_t off, int count, int *eof, void *data);
127
128/* Map bus/device to device_id */
129static int _pcie_bus_devfv_to_devid(int bus, int devfn)
130{
131 const bus_devfn_devid *map;
132 for (map = bcmolt_board_pci_map_table_get(); map && map->bus > 0; map++)
133 {
134 if (map->bus == bus && map->devfn == devfn)
135 {
136 return map->device;
137 }
138 }
139 /* Not found - use incremental mapping */
140 return crt_device;
141}
142
143/* procedure used by OS to connect Maple PCI to allocated memory */
144
145static int __devinit maple_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
146{
147 int rc;
148 volatile unsigned int readval;
149 maple_device_info *device_info = NULL;
150 int dev_id;
151 u32 val;
152
153 if (!pdev)
154 return 1;
155
156 dev_info(&pdev->dev,
157 "Bus = %d Slot = %d Vendor:device = 0x%04x:0x%04x revision = 0x%02x\n",
158 pdev->bus->number, pdev->devfn,
159 pdev->vendor, pdev->device, pdev->revision);
160
161 if (crt_device == MAPLE_MAX_DEVICES)
162 {
163 printk(" Maximum Maple devices already defined (%d)\n", MAPLE_MAX_DEVICES);
164 return -ENODEV;
165 }
166
167 dev_id = _pcie_bus_devfv_to_devid(pdev->bus->number, pdev->devfn);
168 ++crt_device;
169 device_info = &devices[dev_id];
170 memset(device_info, 0, sizeof(maple_device_info));
171
172 spin_lock_init(&device_info->lock);
173 device_info->deviceid = dev_id;
174 device_info->pdev = pdev;
175
176 /* Enable maple device on PCIe bus and fixup BARs.
177 * Without fixup, module unload/reload crashes with WRX host
178 * because PCI hotplug doesn't work and after unload/re-load
179 * linux believes that BARs are already set.
180 */
181 rc = bcm_ll_pcie_dev_enable(dev_id);
182 if (rc)
183 {
184 printk("Error pci_enable_device_mem = %d\n",rc);
185 goto err_out;
186 }
187
188 rc = pci_request_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM), DRV_NAME);
189 if (rc)
190 goto err_out;
191
192 pci_set_master(pdev);
193 pci_save_state(pdev);
194
195 device_info->device.soc_regs_base = (unsigned long)pci_ioremap_bar(pdev, BAR_REGS);
196 device_info->device.soc_sram_base = (unsigned long)pci_ioremap_bar(pdev, BAR_SRAM);
197 device_info->device.soc_ddr_base = (unsigned long)pci_ioremap_bar(pdev, BAR_DDR);
198 device_info->device.soc_ddr_length = (uint32_t)pci_resource_len(pdev, BAR_DDR);
199 device_info->device.irq = pdev->irq;
200 pci_set_drvdata(pdev, device_info);
201
202 //rc = request_irq(device_info->device.irq, maple_interrupt, IRQF_SHARED, "maple-pcie", device_info);
203 if (!rc && device_info->device.soc_sram_base)
204 {
205 device_info->device.irq_connected = 1;
206 readval = bcm_pci_read32((uint32_t *)(device_info->device.soc_regs_base + PCIE_REVISION_REGISTER_OFFSET));
207 printk("Card %d version major=%02x minor=%02x\n",device_info->deviceid,
208 ((readval & 0x0000ff00) >> 8),(readval & 0x000000ff));
209 printk("regs_start = 0x%lx\nddr_start = 0x%lx\nsram_start = 0x%lx\nddr_length = %d\n",
210 device_info->device.soc_regs_base,device_info->device.soc_ddr_base,
211 device_info->device.soc_sram_base, (int)device_info->device.soc_ddr_length);
212 pci_read_config_dword(pdev,PCI_BASE_ADDRESS_0,&val);
213 printk("BAR REGS = 0x%x\n",(unsigned int)val);
214 pci_read_config_dword(pdev,PCI_BASE_ADDRESS_2,&val);
215 printk("BAR DDR = 0x%x\n",(unsigned int)val);
216 pci_read_config_dword(pdev,PCI_BASE_ADDRESS_4,&val);
217 printk("BAR SRAM = 0x%x\n",(unsigned int)val);
218 readval = bcm_pci_read32((uint32_t *)(device_info->device.soc_regs_base + PCIE_STATUS_REGISTER_OFFSET));
219 device_info->err_status = readval & 0x0000000f;
220 device_info->phylink = (readval >> 4) & 0x1;
221 device_info->datalink = (readval >> 5) & 0x1;
222 device_info->prev_datalink = device_info->datalink;
223 }
224 else
225 goto err_out;
226
227 return rc;
228
229err_out:
230 pci_disable_device (pdev);
231 memset(device_info, 0, sizeof(*device_info));
232 --crt_device;
233
234 return rc;
235}
236
237static void __devexit maple_pci_remove(struct pci_dev *pdev)
238{
239 int i;
240 maple_device_info *dev = pci_get_drvdata(pdev);
241
242 if (!dev)
243 return;
244
245 if (dev->device.irq_connected)
246 {
247 //free_irq(dev->device.irq, dev);
248 dev->device.irq_connected = 0;
249 }
250 if (callback)
251 {
252 for (i = 0; i < crt_device; i++)
253 {
254 if (devices[i].pdev == pdev)
255 {
256 callback(i, BCM_LL_PCIE_LINK_DOWN);
257 break;
258 }
259 }
260 }
261 pci_disable_device(pdev);
262 pci_release_regions(pdev);
263 pci_set_drvdata(pdev, NULL);
264 dev->device.soc_sram_base = 0;
265 dev->device.soc_regs_base = 0;
266 dev->pdev = NULL;
267}
268
269static struct pci_driver maple_pci_driver = {
270 .name = DRV_NAME,
271 .id_table = maple_pci_tbl,
272 .probe = maple_pci_probe,
273 .remove = __devexit_p(maple_pci_remove),
274};
275
276static maple_device_info *get_maple_pci_info(int crt)
277{
278 unsigned int readval=0;
279 maple_device_info *device;
280
281 if (crt >= BCMTR_MAX_OLTS)
282 return NULL;
283
284 device = &devices[crt];
285 if (device->device.soc_regs_base)
286 {
287 if (device->enabled)
288 {
289 readval = bcm_pci_read32((uint32_t *)(device->device.soc_regs_base + PCIE_STATUS_REGISTER_OFFSET));
290 device->err_status = readval & 0x0000000f;
291 device->phylink = (readval >> 4) & 0x1;
292 device->datalink = (readval >> 5) & 0x1;
293 }
294 else
295 {
296 device->err_status = 0;
297 device->phylink = 0;
298 device->datalink = 0;
299 }
300 }
301 else
302 device = NULL;
303
304 return device;
305}
306
307#if 0
308static irqreturn_t maple_interrupt (int irq, void *dev_instance)
309{
310 volatile unsigned int value;
311 maple_device_info *device_info;
312 unsigned long flags;
313 int handled = IRQ_NONE;
314 uint32_t device;
315
316 spin_lock_irqsave(&device_info->lock, flags);
317 value = bcm_pci_read32((uint32_t *)(device_info->device.soc_regs_base + PCIE_INT_STATUS_REGISTER_OFFSET));
318 if (value)
319 {
320 if (device_info->datalink != device_info->prev_datalink)
321 {
322 if (device_info->datalink == BCM_LL_PCIE_LINK_UP)
323 printk("Device=%d : Link is up !!!\n", device);
324 else
325 {
326 printk("Device=%d : Link is down !!!\n", device);
327 printk("phy status = 0x%x error status = 0x%x\n", device_info->phylink, device_info->err_status);
328 }
329 device_info->prev_datalink = device_info->datalink;
330 if (callback)
331 callback(device, device_info->datalink);
332 }
333 value = bcm_pci_read32((uint32_t *)(device_info->device.soc_regs_base + PCIE_INTR1_STATUS_REGISTER_OFFSET));
334 if (!value)
335 handled = IRQ_HANDLED;
336 }
337 spin_unlock_irqrestore(&device_info->lock, flags);
338
339 return IRQ_RETVAL(handled);
340}
341#endif
342
343/* Returns BAR register address */
344static int _pci_bar_reg_addr(int res)
345{
346 return 0x10 + res*4;
347}
348
349static void _pci_update_resource(struct pci_dev *dev, int resno)
350{
351 struct pci_bus_region region;
352 u16 cmd;
353 u32 new, check, mask;
354 int reg;
355 struct resource *res = dev->resource + resno;
356
357 /*
358 * Ignore resources for unimplemented BARs and unused resource slots
359 * for 64 bit BARs.
360 */
361 if (!res->flags)
362 return;
363
364 /*
365 * Ignore non-moveable resources. This might be legacy resources for
366 * which no functional BAR register exists or another important
367 * system resource we shouldn't move around.
368 */
369 if (res->flags & IORESOURCE_PCI_FIXED)
370 return;
371
372 pcibios_resource_to_bus(dev, &region, res);
373
374 new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
375 if (res->flags & IORESOURCE_IO)
376 mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
377 else
378 mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
379
380 reg = _pci_bar_reg_addr(resno);
381
382 pci_write_config_dword(dev, reg, new);
383 pci_read_config_dword(dev, reg, &check);
384
385 if ((new ^ check) & mask) {
386 dev_err(&dev->dev, "BAR %d: error updating (%#08x != %#08x)\n",
387 resno, new, check);
388 }
389
390 if (res->flags & IORESOURCE_MEM_64) {
391 new = region.start >> 16 >> 16;
392 pci_write_config_dword(dev, reg + 4, new);
393 pci_read_config_dword(dev, reg + 4, &check);
394 if (check != new) {
395 dev_err(&dev->dev, "BAR %d: error updating "
396 "(high %#08x != %#08x)\n", resno, new, check);
397 }
398 }
399
400 pci_read_config_word(dev, PCI_COMMAND, &cmd);
401 pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
402
403 res->flags &= ~IORESOURCE_UNSET;
404 dev_info(&dev->dev, "BAR %d: set to %pR (PCI address [%#llx-%#llx])\n",
405 resno, res, (unsigned long long)region.start,
406 (unsigned long long)region.end);
407}
408
409/* Enable PCI access to device */
410bcmos_errno bcm_ll_pcie_dev_enable(int dev_id)
411{
412 maple_device_info *device;
413 int rc;
414
415 if (dev_id >= MAPLE_MAX_DEVICES)
416 return BCM_ERR_PARM;
417
418 device = &devices[dev_id];
419 if (!device->pdev)
420 return BCM_ERR_IO;
421
422 rc = pci_enable_device_mem(device->pdev);
423 if (rc)
424 {
425 printk("Error pci_enable_device_mem for device %d = %d\n", dev_id, rc);\
426 goto out;
427 }
428
429 /* Refresh devices's PCIe header */
430 _pci_update_resource(device->pdev, BAR_REGS);
431 _pci_update_resource(device->pdev, BAR_SRAM);
432 _pci_update_resource(device->pdev, BAR_DDR);
433 device->enabled = 1;
434
435out:
436 return rc ? BCM_ERR_IO : BCM_ERR_OK;
437}
438
439/* Disable PCI access to device */
440bcmos_errno bcm_ll_pcie_dev_disable(int dev_id)
441{
442 maple_device_info *device;
443
444 printk("%s: device %d\n", __FUNCTION__, dev_id);
445
446 if (dev_id >= MAPLE_MAX_DEVICES)
447 return BCM_ERR_PARM;
448
449 device = &devices[dev_id];
450 if (!device->pdev || !device->enabled)
451 return BCM_ERR_OK;
452 pci_disable_device(device->pdev);
453 device->enabled = 0;
454
455 return BCM_ERR_OK;
456}
457
458bcmos_errno bcm_ll_pcie_init(void)
459{
460 int rc;
461 if (is_initialized)
462 return BCM_ERR_OK;
463 is_initialized = BCMOS_TRUE;
464 rc = pci_register_driver(&maple_pci_driver);
465 printk(KERN_INFO "Maple PCI driver registered with PCI subsystem. rc=%d\n", rc);
466 return rc ? BCM_ERR_INTERNAL : BCM_ERR_OK;
467}
468
469void bcm_ll_pcie_cleanup(void)
470{
471 if (!is_initialized)
472 return;
473 is_initialized = BCMOS_FALSE;
474
475 pci_unregister_driver(&maple_pci_driver);
476 crt_device = 0;
477 memset(devices, 0, sizeof(devices));
478}
479
480/*******************************************/
481/* procedures executed on insmod and rmmod */
482/*******************************************/
483static int __init bcm_ll_init_module(void)
484{
485 struct proc_dir_entry *bcmolt_file = NULL;
486
487 if ((bcmolt_dir = create_proc_entry("bcmolt", S_IFDIR, NULL)) == NULL)
488 {
489 printk("Unable to create /proc/bcmolt entry\n");
490 return -1;
491 }
492 if ((bcmolt_file = create_proc_entry("card", S_IFREG | S_IWUSR | S_IRUGO, bcmolt_dir)) == NULL)
493 {
494 printk("Unable to create /proc/bcmolt/card entry\n");
495 remove_proc_entry("bcmolt", bcmolt_dir);
496 return -1;
497 }
498 bcmolt_file->write_proc = (write_proc_t *)maple_write;
499 bcmolt_file->read_proc = (read_proc_t *)maple_read;
500
501 return 0;
502}
503
504static void __exit bcm_ll_cleanup_module(void)
505{
506 bcm_ll_pcie_cleanup();
507 remove_proc_entry("card", bcmolt_dir);
508 remove_proc_entry("bcmolt", NULL);
509 printk("Unregister done\n");
510}
511
512/*****************************/
513/* APIs used by Host drivers */
514/*****************************/
515bcmos_errno bcm_ll_pcie_status_change_register(bcm_ll_pcie_status_change cb)
516{
517 int i;
518 maple_device_info *device_info;
519
520 callback = cb;
521 if(callback)
522 {
523 for (i = 0; i < crt_device; i++)
524 {
525 device_info = get_maple_pci_info(i);
526 if (device_info)
527 callback(i, device_info->datalink);
528 else
529 callback(i, BCM_LL_PCIE_LINK_DOWN);
530 }
531 }
532
533 return BCM_ERR_OK;
534}
535
536bcmos_errno bcm_ll_pcie_status_change_unregister(void)
537{
538 callback = NULL;
539
540 return BCM_ERR_OK;
541}
542
543bcmos_errno bcm_ll_pcie_query(uint8_t dev_id, bcm_ll_dev_info *info)
544{
545 maple_device_info *device_info;
546
547 if (!info)
548 return BCM_ERR_PARM;
549
550 if (dev_id < MAPLE_MAX_DEVICES)
551 {
552 device_info = get_maple_pci_info(dev_id);
553 if (device_info && device_info->pdev)
554 {
555 if (device_info->datalink == BCM_LL_PCIE_LINK_DOWN)
556 return BCM_ERR_IO;
557 *info = device_info->device;
558 return BCM_ERR_OK;
559 }
560 return BCM_ERR_IO;
561 }
562 return BCM_ERR_RANGE;
563}
564
565bcm_ll_pcie_dev bcm_ll_pcie_dev_get(uint8_t dev_id)
566{
567 maple_device_info *device_info;
568
569 if (dev_id < crt_device)
570 {
571 device_info = get_maple_pci_info(dev_id);
572 return (device_info ? device_info->pdev : NULL);
573 }
574
575 return NULL;
576}
577
578bcmos_errno bcm_ll_pcie_host_reset_enable(uint8_t dev_id, bcmos_bool enabled)
579{
580 uint32_t val;
581
582 val = enabled ? 0 : 1;
583 bcm_pci_write32((uint32_t *)(devices[dev_id].device.soc_regs_base + PCIE_HARD_DEBUG_REGISTER_OFFSET), val);
584
585 return BCM_ERR_OK;
586}
587
588#ifdef TX_ENABLE_EVENT_TRACE
589bcmos_errno bcm_ll_pcie_setrace(uint8_t dev_id)
590{
591 maple_device_info *device_info;
592 uint32_t val,lim,base,size;
593 uint32_t reglo,reghi,baselim;
594 unsigned long addr;
595
596 if (dev_id < crt_device)
597 {
598 device_info = &devices[dev_id];
599 if (!device_info)
600 return BCM_ERR_IO;
601 size = EVENT_BUFFER_SIZE;
602 device_info->traceaddr = (unsigned int *)bcmos_alloc_not_cache(size);
603 memset(device_info->traceaddr,0,size);
604 addr = bcmos_virt_to_phys(device_info->traceaddr); /* | 0x02 = reverse byte order = swap */
605 printk("trace window : alloc=0x%lx size=0x%x\n",(unsigned long)device_info->traceaddr, (unsigned int)size);
606 reglo = PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_LO;
607 reghi = PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_HI;
608 baselim = PCIE_PCIE_0_MISC_CPU_2_PCIE_MEM_WIN1_BASE_LIMIT;
609 bcm_pci_write32((uint32_t *)(device_info->device.soc_regs_base + reglo),addr & 0xffffffff);
610 bcm_pci_write32((uint32_t *)(device_info->device.soc_regs_base + reghi)),((addr >> 32) & 0xffffffff);
611 /* base */
612 base = CPU_2_PCIE_MEM_WIN1_BASE;
613 /* limit */
614 lim = base + size;
615 val = lim | (base >> 16);
616 bcm_pci_write32((uint32_t *)(device_info->device.soc_regs_base + baselim),val);
617 //bcm_fld_set_event_trace(dev_id);
618 bcm_pci_write32((uint32_t *)(device_info->device.soc_sram_base + BCM_FLD_EVENT_TRACE_OFFSET),0x1);
619
620 return BCM_ERR_OK;
621 }
622 return BCM_ERR_RANGE;
623}
624bcmos_errno bcm_ll_pcie_cleartrace(uint8_t dev_id)
625{
626 maple_device_info *device_info;
627
628 if (dev_id < crt_device)
629 {
630 device_info = &devices[dev_id];
631 if (!device_info)
632 return BCM_ERR_IO;
633 //bcm_fld_clear_event_trace(dev_id);
634 bcm_pci_write32((uint32_t *)(device_info->device.soc_sram_base + BCM_FLD_EVENT_TRACE_OFFSET),0x0);
635 return BCM_ERR_OK;
636 }
637 return BCM_ERR_RANGE;
638}
639bcmos_errno bcm_ll_pcie_savetrace(uint8_t dev_id, char *tracefilename)
640{
641 maple_device_info *device_info;
642 struct file *fp;
643 unsigned long seg = 0;
644 mm_segment_t memseg;
645
646 if (!tracefilename)
647 return BCM_ERR_PARM;
648
649 printk("device=%d from=%d, Go to write to file %s\n",dev_id , crt_device, tracefilename);
650
651 if (dev_id < crt_device)
652 {
653 device_info = &devices[dev_id];
654 if (!device_info)
655 {
656 printk("Error: device_info is null\n");
657 goto exit;
658 }
659 fp = filp_open(tracefilename, O_WRONLY | O_CREAT, 0666);
660 if ((fp == NULL) || (fp == (void *)-ENOENT))
661 {
662 printk("Error: Can't open file %s\n",tracefilename);
663 goto exit;
664 }
665 // Get current segment descriptor
666 seg = get_fs().seg;
667
668 // Set segment descriptor associated to kernel space
669 set_fs(get_ds());
670 fp->f_op->write(fp, (char *)device_info->traceaddr,EVENT_BUFFER_SIZE, &fp->f_pos);
671
672 memseg.seg = seg;
673 set_fs(memseg);
674 filp_close(fp, NULL);
675 printk("Wrote file %s\n",tracefilename);
676exit:
677 bcmos_free_not_cache(device_info->traceaddr);
678
679 return BCM_ERR_OK;
680 }
681 return BCM_ERR_RANGE;
682}
683#endif
684
685/*************************************************************/
686/* User interface functions : implement echo/cat to proc file*/
687/*************************************************************/
688
689typedef struct
690{
691 char *name;
692 void (*callback)(int cmdid, char *cmd);
693 char *description;
694} maple_card_command;
695
696static char *find_command(char *cmd);
697static void command_reg(int cmdid, char *line);
698static void command_mem(int cmdid, char *line);
699static void command_cfg(int cmdid, char *line);
700#ifdef TX_ENABLE_EVENT_TRACE
701static void command_trace(int cmdid, char *line);
702#endif
703
704#define READCMD 0
705#define WRITECMD 1
706
707static maple_card_command commands[] =
708{
709 {"readreg", command_reg, "read register <index> <register offset - hex>"},
710 {"writereg", command_reg, "write register <index> <register offset - hex> <value - hex>"},
711 {"read", command_mem, "read <address - hex> <number of words - dec>"},
712 {"write", command_mem, "write <address - hex> <value - hex>"},
713 {"rcfg", command_cfg, "read dev <address - hex> <number of words - dec>"},
714 {"wcfg", command_cfg, "write dev <address - hex> <value - hex>"},
715#ifdef TX_ENABLE_EVENT_TRACE
716 {"trace", command_trace, "trace <index> on/off/save tx trace"},
717#endif
718 {NULL, NULL, NULL}
719};
720
721static char *find_command(char *cmd)
722{
723 char *rest;
724 int i = 0;
725 maple_card_command *cmdptr = &commands[0];
726
727 cmd = skip_spaces(cmd);
728 if (!strncmp(cmd,"help",strlen("help")))
729 {
730 while (cmdptr->name)
731 {
732 printk("%s\t: %s\n",cmdptr->name, cmdptr->description);
733 cmdptr = &commands[++i];
734 }
735 return NULL;
736 }
737 while (cmdptr->name)
738 {
739 if (!strncmp(cmdptr->name, cmd, strlen(cmdptr->name)))
740 {
741 rest = cmd + strlen(cmdptr->name);
742 rest = skip_spaces(rest);
743 cmdptr->callback(i%2, rest);
744 return NULL;
745 }
746 cmdptr = &commands[++i];
747 }
748
749 return "Wrong command name";
750}
751/**********************************************************************
752 answers to cat /proc/bcmolt command
753**********************************************************************/
754static int maple_read(char *page, char **start, off_t off, int count, int *eof, void *data)
755{
756 int i;
757 int len;
758 maple_device_info *dev = NULL;
759
760 len = sprintf(page, "Maple Device Info\n\n");
761 for (i = 0; i < MAPLE_MAX_DEVICES; i++)
762 {
763 dev = get_maple_pci_info(i);
764 if (dev)
765 {
766 len += sprintf(page + len, "id=%d regs_start=0x%lx ddr_start=0x%lx sram_start=0x%lx ddr_length=%d\n",
767 dev->deviceid,
768 dev->device.soc_regs_base,dev->device.soc_ddr_base,
769 dev->device.soc_sram_base, (int)dev->device.soc_ddr_length);
770 len += sprintf(page + len, "Phy Link is %s Data Link is %s Error status = %d\n\n",
771 dev->phylink == 1 ? "UP" : "DOWN", dev->datalink == 1 ? "UP" : "DOWN", (int)dev->err_status);
772 }
773 }
774
775 return len;
776}
777#ifdef TX_ENABLE_EVENT_TRACE
778static void command_trace(int cmdid, char *line)
779{
780 char token[5];
781 int index;
782
783 if (sscanf(line, "%d %s", &index, token) != 2)
784 {
785 printk("Wrong parameter\n");
786 return;
787 }
788 printk("TRACE commands : %s\n",token);
789 if (!strncmp(token,"on",2))
790 {
791 //on
792 bcm_ll_pcie_setrace(index);
793 return;
794 }
795 if (!strncmp(token,"off",3))
796 {
797 // off
798 bcm_ll_pcie_cleartrace(index);
799 return;
800 }
801 if (!strncmp(token,"save",4))
802 {
803 //get
804 char filename[20];
805 sprintf(filename,"./tt_trace_%d.trx",index);
806 bcm_ll_pcie_savetrace(index,filename);
807 return;
808 }
809 printk("Wrong command\n");
810}
811#endif
812
813
814static void command_reg(int cmdindex, char *line)
815{
816 char *rest;
817 char *token;
818 int index;
819 unsigned long address;
820 unsigned int reg;
821
822 if (sscanf(line, "%d %lx", &index, &address) != 2)
823 {
824 printk("Wrong parameter\n");
825 return;
826 }
827 address += (unsigned long)devices[index].device.soc_regs_base;
828 switch (cmdindex)
829 {
830 case READCMD:
831 reg = bcm_pci_read32((uint32_t *)address);
832 printk("0x%lx : %08x\n", address, reg);
833 break;
834 case WRITECMD:
835 rest = line;
836 token = strsep(&rest, " "); /* skip index */
837 token = strsep(&rest, " "); /* skip address */
838 token = strsep(&rest, " ");
839 if (!token)
840 {
841 printk("Wrong parameter\n");
842 return;
843 }
844 sscanf(token, "%x", &reg);
845 printk("write 0x%x to 0x%lx\n", reg, address);
846 bcm_pci_write32((uint32_t *)address,reg);
847 break;
848 }
849}
850
851static void command_mem(int cmdindex, char *line)
852{
853 char *token;
854 char *rest;
855 unsigned long address;
856 unsigned int reg;
857 int i, number_of_words;
858 int in_line=0, max_in_line;
859
860 if (sscanf(line, "%lx", &address) != 1)
861 {
862 printk("Wrong parameter\n");
863 return;
864 }
865 rest = line;
866 token = strsep(&rest, " "); /* skip address */
867 switch (cmdindex)
868 {
869 case READCMD:
870 token = strsep(&rest, " ");
871 if (!token)
872 number_of_words = 1;
873 else
874 sscanf(token, "%d", &number_of_words);
875
876 max_in_line = 4;
877 for (i = 0; i < number_of_words; i++, address += 4)
878 {
879 if (!in_line)
880 printk("%08lx: ", address);
881 reg = bcm_pci_read32((uint32_t *)address);
882 printk("%08x", reg);
883 if (++in_line < max_in_line)
884 printk(" ");
885 else
886 {
887 printk("\n");
888 in_line = 0;
889 }
890 }
891 if (in_line)
892 printk("\n");
893 break;
894 case WRITECMD:
895 token = strsep(&rest, " ");
896 if (!token)
897 {
898 printk("Wrong parameter\n");
899 return;
900 }
901 sscanf(token, "%x", &reg);
902 bcm_pci_write32((uint32_t *)address,reg);
903 break;
904 }
905}
906
907static void command_cfg(int cmdindex, char *line)
908{
909 unsigned long address;
910 unsigned int reg;
911 unsigned int val_or_num;
912 int crt;
913 int i;
914 int in_line=0, max_in_line;
915 maple_device_info *device;
916
917 if (sscanf(line, "%d %lx %x", &crt, &address, &val_or_num) != 3)
918 {
919 printk("Wrong parameter\n");
920 return;
921 }
922
923 if (crt >= crt_device || !devices[crt].pdev)
924 {
925 printk("Invalid device %d\n", crt);
926 return;
927 }
928
929 device = &devices[crt];
930
931 switch (cmdindex)
932 {
933 case READCMD:
934 max_in_line = 4;
935 for (i = 0; i < val_or_num; i++, address += 4)
936 {
937 if (!in_line)
938 printk("%08lx: ", address);
939 pci_read_config_dword(device->pdev, address, &reg);
940 printk("%08x", reg);
941 if (++in_line < max_in_line)
942 printk(" ");
943 else
944 {
945 printk("\n");
946 in_line = 0;
947 }
948 }
949 if (in_line)
950 printk("\n");
951 break;
952
953 case WRITECMD:
954 pci_write_config_dword(device->pdev, address, val_or_num);
955 break;
956 }
957}
958
959/**********************************************************************
960 answers to echo [...] > /proc/bcmolt command
961**********************************************************************/
962static int maple_write(struct file *file,const char *buffer,size_t count, void *data)
963{
964 char *internal;
965
966 if (buffer == NULL)
967 return -EFAULT;
968
969 internal = kmalloc(count, GFP_KERNEL);
970 if (!internal)
971 {
972 printk("Not enough memmory\n");
973 return count;
974 }
975
976 memset(internal, 0, count);
977 if (copy_from_user(internal, buffer, count))
978 {
979 printk("Not enough memmory\n");
980 goto error;
981 }
982 find_command(internal);
983
984error:
985 kfree(internal);
986
987 return count;
988}
989
990EXPORT_SYMBOL(bcmolt_dir);
991EXPORT_SYMBOL(bcm_ll_pcie_init);
992EXPORT_SYMBOL(bcm_ll_pcie_cleanup);
993EXPORT_SYMBOL(bcm_ll_pcie_status_change_register);
994EXPORT_SYMBOL(bcm_ll_pcie_status_change_unregister);
995EXPORT_SYMBOL(bcm_ll_pcie_query);
996EXPORT_SYMBOL(bcm_ll_pcie_dev_get);
997EXPORT_SYMBOL(bcm_ll_pcie_dev_enable);
998EXPORT_SYMBOL(bcm_ll_pcie_dev_disable);
999EXPORT_SYMBOL(bcm_ll_pcie_host_reset_enable);
1000
1001#ifdef TX_ENABLE_EVENT_TRACE
1002EXPORT_SYMBOL(bcm_ll_pcie_setrace);
1003EXPORT_SYMBOL(bcm_ll_pcie_cleartrace);
1004EXPORT_SYMBOL(bcm_ll_pcie_savetrace);
1005#endif
1006module_init(bcm_ll_init_module);
1007module_exit(bcm_ll_cleanup_module);
1008
1009MODULE_DESCRIPTION("maple line card");
1010MODULE_LICENSE("Dual BSD/GPL");