linux/drivers/atm/fore200e.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
  A FORE Systems 200E-series driver for ATM on Linux.
  Christophe Lizzi ([email protected]), October 1999-March 2003.

  Based on the PCA-200E driver from Uwe Dannowski ([email protected]).

  This driver simultaneously supports PCA-200E and SBA-200E adapters
  on i386, alpha (untested), powerpc, sparc and sparc64 architectures.

*/


#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/capability.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/atmdev.h>
#include <linux/sonet.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/pgtable.h>
#include <asm/io.h>
#include <asm/string.h>
#include <asm/page.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/byteorder.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>

#ifdef CONFIG_SBUS
#include <linux/of.h>
#include <linux/platform_device.h>
#include <asm/idprom.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#endif

#if defined(CONFIG_ATM_FORE200E_USE_TASKLET) /* defer interrupt work to a tasklet */
#define FORE200E_USE_TASKLET
#endif

#if 0 /* enable the debugging code of the buffer supply queues */
#define FORE200E_BSQ_DEBUG
#endif

#if 1 /* ensure correct handling of 52-byte AAL0 SDUs expected by atmdump-like apps */
#define FORE200E_52BYTE_AAL0_SDU
#endif

#include "fore200e.h"
#include "suni.h"

#define FORE200E_VERSION

#define FORE200E

#if 0 /* override .config */
#define CONFIG_ATM_FORE200E_DEBUG
#endif
#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0)
#define DPRINTK
#else
#define DPRINTK(level, format, args...)
#endif


#define FORE200E_ALIGN(addr, alignment)

#define FORE200E_DMA_INDEX(dma_addr, type, index)

#define FORE200E_INDEX(virt_addr, type, index)

#define FORE200E_NEXT_ENTRY(index, modulo)

#if 1
#define ASSERT(expr)
#else
#define ASSERT
#endif


static const struct atmdev_ops   fore200e_ops;

MODULE_AUTHOR();
MODULE_DESCRIPTION();

static const int fore200e_rx_buf_nbr[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] =;

static const int fore200e_rx_buf_size[ BUFFER_SCHEME_NBR ][ BUFFER_MAGN_NBR ] =;


#if defined(CONFIG_ATM_FORE200E_DEBUG) && (CONFIG_ATM_FORE200E_DEBUG > 0)
static const char* fore200e_traffic_class[] = { "NONE", "UBR", "CBR", "VBR", "ABR", "ANY" };
#endif


#if 0 /* currently unused */
static int 
fore200e_fore2atm_aal(enum fore200e_aal aal)
{
    switch(aal) {
    case FORE200E_AAL0:  return ATM_AAL0;
    case FORE200E_AAL34: return ATM_AAL34;
    case FORE200E_AAL5:  return ATM_AAL5;
    }

    return -EINVAL;
}
#endif


static enum fore200e_aal
fore200e_atm2fore_aal(int aal)
{}


static char*
fore200e_irq_itoa(int irq)
{}


/* allocate and align a chunk of memory intended to hold the data behing exchanged
   between the driver and the adapter (using streaming DVMA) */

static int
fore200e_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk, int size, int alignment, int direction)
{}


/* free a chunk of memory */

static void
fore200e_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
{}

/*
 * Allocate a DMA consistent chunk of memory intended to act as a communication
 * mechanism (to hold descriptors, status, queues, etc.) shared by the driver
 * and the adapter.
 */
static int
fore200e_dma_chunk_alloc(struct fore200e *fore200e, struct chunk *chunk,
		int size, int nbr, int alignment)
{}

/*
 * Free a DMA consistent chunk of memory.
 */
static void
fore200e_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
{}

static void
fore200e_spin(int msecs)
{}


static int
fore200e_poll(struct fore200e* fore200e, volatile u32* addr, u32 val, int msecs)
{}


static int
fore200e_io_poll(struct fore200e* fore200e, volatile u32 __iomem *addr, u32 val, int msecs)
{}


static void
fore200e_free_rx_buf(struct fore200e* fore200e)
{}


static void
fore200e_uninit_bs_queue(struct fore200e* fore200e)
{}


static int
fore200e_reset(struct fore200e* fore200e, int diag)
{}


static void
fore200e_shutdown(struct fore200e* fore200e)
{}


#ifdef CONFIG_PCI

static u32 fore200e_pca_read(volatile u32 __iomem *addr)
{}


static void fore200e_pca_write(u32 val, volatile u32 __iomem *addr)
{}

static int
fore200e_pca_irq_check(struct fore200e* fore200e)
{}


static void
fore200e_pca_irq_ack(struct fore200e* fore200e)
{}


static void
fore200e_pca_reset(struct fore200e* fore200e)
{}


static int fore200e_pca_map(struct fore200e* fore200e)
{}


static void
fore200e_pca_unmap(struct fore200e* fore200e)
{}


static int fore200e_pca_configure(struct fore200e *fore200e)
{}


static int __init
fore200e_pca_prom_read(struct fore200e* fore200e, struct prom_data* prom)
{}


static int
fore200e_pca_proc_read(struct fore200e* fore200e, char *page)
{}

static const struct fore200e_bus fore200e_pci_ops =;
#endif /* CONFIG_PCI */

#ifdef CONFIG_SBUS

static u32 fore200e_sba_read(volatile u32 __iomem *addr)
{
    return sbus_readl(addr);
}

static void fore200e_sba_write(u32 val, volatile u32 __iomem *addr)
{
    sbus_writel(val, addr);
}

static void fore200e_sba_irq_enable(struct fore200e *fore200e)
{
	u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
	fore200e->bus->write(hcr | SBA200E_HCR_INTR_ENA, fore200e->regs.sba.hcr);
}

static int fore200e_sba_irq_check(struct fore200e *fore200e)
{
	return fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_INTR_REQ;
}

static void fore200e_sba_irq_ack(struct fore200e *fore200e)
{
	u32 hcr = fore200e->bus->read(fore200e->regs.sba.hcr) & SBA200E_HCR_STICKY;
	fore200e->bus->write(hcr | SBA200E_HCR_INTR_CLR, fore200e->regs.sba.hcr);
}

static void fore200e_sba_reset(struct fore200e *fore200e)
{
	fore200e->bus->write(SBA200E_HCR_RESET, fore200e->regs.sba.hcr);
	fore200e_spin(10);
	fore200e->bus->write(0, fore200e->regs.sba.hcr);
}

static int __init fore200e_sba_map(struct fore200e *fore200e)
{
	struct platform_device *op = to_platform_device(fore200e->dev);
	unsigned int bursts;

	/* gain access to the SBA specific registers  */
	fore200e->regs.sba.hcr = of_ioremap(&op->resource[0], 0, SBA200E_HCR_LENGTH, "SBA HCR");
	fore200e->regs.sba.bsr = of_ioremap(&op->resource[1], 0, SBA200E_BSR_LENGTH, "SBA BSR");
	fore200e->regs.sba.isr = of_ioremap(&op->resource[2], 0, SBA200E_ISR_LENGTH, "SBA ISR");
	fore200e->virt_base    = of_ioremap(&op->resource[3], 0, SBA200E_RAM_LENGTH, "SBA RAM");

	if (!fore200e->virt_base) {
		printk(FORE200E "unable to map RAM of device %s\n", fore200e->name);
		return -EFAULT;
	}

	DPRINTK(1, "device %s mapped to 0x%p\n", fore200e->name, fore200e->virt_base);
    
	fore200e->bus->write(0x02, fore200e->regs.sba.isr); /* XXX hardwired interrupt level */

	/* get the supported DVMA burst sizes */
	bursts = of_getintprop_default(op->dev.of_node->parent, "burst-sizes", 0x00);

	if (sbus_can_dma_64bit())
		sbus_set_sbus64(&op->dev, bursts);

	fore200e->state = FORE200E_STATE_MAP;
	return 0;
}

static void fore200e_sba_unmap(struct fore200e *fore200e)
{
	struct platform_device *op = to_platform_device(fore200e->dev);

	of_iounmap(&op->resource[0], fore200e->regs.sba.hcr, SBA200E_HCR_LENGTH);
	of_iounmap(&op->resource[1], fore200e->regs.sba.bsr, SBA200E_BSR_LENGTH);
	of_iounmap(&op->resource[2], fore200e->regs.sba.isr, SBA200E_ISR_LENGTH);
	of_iounmap(&op->resource[3], fore200e->virt_base,    SBA200E_RAM_LENGTH);
}

static int __init fore200e_sba_configure(struct fore200e *fore200e)
{
	fore200e->state = FORE200E_STATE_CONFIGURE;
	return 0;
}

static int __init fore200e_sba_prom_read(struct fore200e *fore200e, struct prom_data *prom)
{
	struct platform_device *op = to_platform_device(fore200e->dev);
	const u8 *prop;
	int len;

	prop = of_get_property(op->dev.of_node, "madaddrlo2", &len);
	if (!prop)
		return -ENODEV;
	memcpy(&prom->mac_addr[4], prop, 4);

	prop = of_get_property(op->dev.of_node, "madaddrhi4", &len);
	if (!prop)
		return -ENODEV;
	memcpy(&prom->mac_addr[2], prop, 4);

	prom->serial_number = of_getintprop_default(op->dev.of_node,
						    "serialnumber", 0);
	prom->hw_revision = of_getintprop_default(op->dev.of_node,
						  "promversion", 0);
    
	return 0;
}

static int fore200e_sba_proc_read(struct fore200e *fore200e, char *page)
{
	struct platform_device *op = to_platform_device(fore200e->dev);
	const struct linux_prom_registers *regs;

	regs = of_get_property(op->dev.of_node, "reg", NULL);

	return sprintf(page, "   SBUS slot/device:\t\t%d/'%pOFn'\n",
		       (regs ? regs->which_io : 0), op->dev.of_node);
}

static const struct fore200e_bus fore200e_sbus_ops = {
	.model_name		= "SBA-200E",
	.proc_name		= "sba200e",
	.descr_alignment	= 32,
	.buffer_alignment	= 64,
	.status_alignment	= 32,
	.read			= fore200e_sba_read,
	.write			= fore200e_sba_write,
	.configure		= fore200e_sba_configure,
	.map			= fore200e_sba_map,
	.reset			= fore200e_sba_reset,
	.prom_read		= fore200e_sba_prom_read,
	.unmap			= fore200e_sba_unmap,
	.irq_enable		= fore200e_sba_irq_enable,
	.irq_check		= fore200e_sba_irq_check,
	.irq_ack		= fore200e_sba_irq_ack,
	.proc_read		= fore200e_sba_proc_read,
};
#endif /* CONFIG_SBUS */

static void
fore200e_tx_irq(struct fore200e* fore200e)
{}


#ifdef FORE200E_BSQ_DEBUG
int bsq_audit(int where, struct host_bsq* bsq, int scheme, int magn)
{
    struct buffer* buffer;
    int count = 0;

    buffer = bsq->freebuf;
    while (buffer) {

	if (buffer->supplied) {
	    printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld supplied but in free list!\n",
		   where, scheme, magn, buffer->index);
	}

	if (buffer->magn != magn) {
	    printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected magn = %d\n",
		   where, scheme, magn, buffer->index, buffer->magn);
	}

	if (buffer->scheme != scheme) {
	    printk(FORE200E "bsq_audit(%d): queue %d.%d, buffer %ld, unexpected scheme = %d\n",
		   where, scheme, magn, buffer->index, buffer->scheme);
	}

	if ((buffer->index < 0) || (buffer->index >= fore200e_rx_buf_nbr[ scheme ][ magn ])) {
	    printk(FORE200E "bsq_audit(%d): queue %d.%d, out of range buffer index = %ld !\n",
		   where, scheme, magn, buffer->index);
	}

	count++;
	buffer = buffer->next;
    }

    if (count != bsq->freebuf_count) {
	printk(FORE200E "bsq_audit(%d): queue %d.%d, %d bufs in free list, but freebuf_count = %d\n",
	       where, scheme, magn, count, bsq->freebuf_count);
    }
    return 0;
}
#endif


static void
fore200e_supply(struct fore200e* fore200e)
{}


static int
fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rpd)
{}


static void
fore200e_collect_rpd(struct fore200e* fore200e, struct rpd* rpd)
{}


static void
fore200e_rx_irq(struct fore200e* fore200e)
{}


#ifndef FORE200E_USE_TASKLET
static void
fore200e_irq(struct fore200e* fore200e)
{
    unsigned long flags;

    spin_lock_irqsave(&fore200e->q_lock, flags);
    fore200e_rx_irq(fore200e);
    spin_unlock_irqrestore(&fore200e->q_lock, flags);

    spin_lock_irqsave(&fore200e->q_lock, flags);
    fore200e_tx_irq(fore200e);
    spin_unlock_irqrestore(&fore200e->q_lock, flags);
}
#endif


static irqreturn_t
fore200e_interrupt(int irq, void* dev)
{}


#ifdef FORE200E_USE_TASKLET
static void
fore200e_tx_tasklet(unsigned long data)
{}


static void
fore200e_rx_tasklet(unsigned long data)
{}
#endif


static int
fore200e_select_scheme(struct atm_vcc* vcc)
{}


static int 
fore200e_activate_vcin(struct fore200e* fore200e, int activate, struct atm_vcc* vcc, int mtu)
{}


#define FORE200E_MAX_BACK2BACK_CELLS

static void
fore200e_rate_ctrl(struct atm_qos* qos, struct tpd_rate* rate)
{}


static int
fore200e_open(struct atm_vcc *vcc)
{}


static void
fore200e_close(struct atm_vcc* vcc)
{}


static int
fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
{}


static int
fore200e_getstats(struct fore200e* fore200e)
{}

#if 0 /* currently unused */
static int
fore200e_get_oc3(struct fore200e* fore200e, struct oc3_regs* regs)
{
    struct host_cmdq*       cmdq  = &fore200e->host_cmdq;
    struct host_cmdq_entry* entry = &cmdq->host_entry[ cmdq->head ];
    struct oc3_opcode       opcode;
    int                     ok;
    u32                     oc3_regs_dma_addr;

    oc3_regs_dma_addr = fore200e->bus->dma_map(fore200e, regs, sizeof(struct oc3_regs), DMA_FROM_DEVICE);

    FORE200E_NEXT_ENTRY(cmdq->head, QUEUE_SIZE_CMD);

    opcode.opcode = OPCODE_GET_OC3;
    opcode.reg    = 0;
    opcode.value  = 0;
    opcode.mask   = 0;

    fore200e->bus->write(oc3_regs_dma_addr, &entry->cp_entry->cmd.oc3_block.regs_haddr);
    
    *entry->status = STATUS_PENDING;

    fore200e->bus->write(*(u32*)&opcode, (u32*)&entry->cp_entry->cmd.oc3_block.opcode);

    ok = fore200e_poll(fore200e, entry->status, STATUS_COMPLETE, 400);

    *entry->status = STATUS_FREE;

    fore200e->bus->dma_unmap(fore200e, oc3_regs_dma_addr, sizeof(struct oc3_regs), DMA_FROM_DEVICE);
    
    if (ok == 0) {
	printk(FORE200E "unable to get OC-3 regs of device %s\n", fore200e->name);
	return -EIO;
    }

    return 0;
}
#endif


static int
fore200e_set_oc3(struct fore200e* fore200e, u32 reg, u32 value, u32 mask)
{}


static int
fore200e_setloop(struct fore200e* fore200e, int loop_mode)
{}


static int
fore200e_fetch_stats(struct fore200e* fore200e, struct sonet_stats __user *arg)
{}


static int
fore200e_ioctl(struct atm_dev* dev, unsigned int cmd, void __user * arg)
{}


static int
fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags)
{}
    

static int fore200e_irq_request(struct fore200e *fore200e)
{}


static int fore200e_get_esi(struct fore200e *fore200e)
{}


static int fore200e_alloc_rx_buf(struct fore200e *fore200e)
{}


static int fore200e_init_bs_queue(struct fore200e *fore200e)
{}


static int fore200e_init_rx_queue(struct fore200e *fore200e)
{}


static int fore200e_init_tx_queue(struct fore200e *fore200e)
{}


static int fore200e_init_cmd_queue(struct fore200e *fore200e)
{}


static void fore200e_param_bs_queue(struct fore200e *fore200e,
				    enum buffer_scheme scheme,
				    enum buffer_magn magn, int queue_length,
				    int pool_size, int supply_blksize)
{}


static int fore200e_initialize(struct fore200e *fore200e)
{}


static void fore200e_monitor_putc(struct fore200e *fore200e, char c)
{}


static int fore200e_monitor_getc(struct fore200e *fore200e)
{}


static void fore200e_monitor_puts(struct fore200e *fore200e, char *str)
{}

#ifdef __LITTLE_ENDIAN
#define FW_EXT
#else
#define FW_EXT
#endif

static int fore200e_load_and_start_fw(struct fore200e *fore200e)
{}


static int fore200e_register(struct fore200e *fore200e, struct device *parent)
{}


static int fore200e_init(struct fore200e *fore200e, struct device *parent)
{}

#ifdef CONFIG_SBUS
static int fore200e_sba_probe(struct platform_device *op)
{
	struct fore200e *fore200e;
	static int index = 0;
	int err;

	fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
	if (!fore200e)
		return -ENOMEM;

	fore200e->bus = &fore200e_sbus_ops;
	fore200e->dev = &op->dev;
	fore200e->irq = op->archdata.irqs[0];
	fore200e->phys_base = op->resource[0].start;

	sprintf(fore200e->name, "SBA-200E-%d", index);

	err = fore200e_init(fore200e, &op->dev);
	if (err < 0) {
		fore200e_shutdown(fore200e);
		kfree(fore200e);
		return err;
	}

	index++;
	dev_set_drvdata(&op->dev, fore200e);

	return 0;
}

static void fore200e_sba_remove(struct platform_device *op)
{
	struct fore200e *fore200e = dev_get_drvdata(&op->dev);

	fore200e_shutdown(fore200e);
	kfree(fore200e);
}

static const struct of_device_id fore200e_sba_match[] = {
	{
		.name = SBA200E_PROM_NAME,
	},
	{},
};
MODULE_DEVICE_TABLE(of, fore200e_sba_match);

static struct platform_driver fore200e_sba_driver = {
	.driver = {
		.name = "fore_200e",
		.of_match_table = fore200e_sba_match,
	},
	.probe		= fore200e_sba_probe,
	.remove_new	= fore200e_sba_remove,
};
#endif

#ifdef CONFIG_PCI
static int fore200e_pca_detect(struct pci_dev *pci_dev,
			       const struct pci_device_id *pci_ent)
{}


static void fore200e_pca_remove_one(struct pci_dev *pci_dev)
{}


static const struct pci_device_id fore200e_pca_tbl[] =;

MODULE_DEVICE_TABLE(pci, fore200e_pca_tbl);

static struct pci_driver fore200e_pca_driver =;
#endif

static int __init fore200e_module_init(void)
{}

static void __exit fore200e_module_cleanup(void)
{}

static int
fore200e_proc_read(struct atm_dev *dev, loff_t* pos, char* page)
{}

module_init();
module_exit(fore200e_module_cleanup);


static const struct atmdev_ops fore200e_ops =;

MODULE_LICENSE();
#ifdef CONFIG_PCI
#ifdef __LITTLE_ENDIAN__
MODULE_FIRMWARE();
#else
MODULE_FIRMWARE("pca200e_ecd.bin2");
#endif
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
MODULE_FIRMWARE("sba200e_ecd.bin2");
#endif