[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <f532cd60414d5b53d7d7766696f3aae81c33c66f.1370856733.git.asnaghi@st.com>
Date: Mon, 10 Jun 2013 14:52:36 +0200
From: Giancarlo Asnaghi <giancarlo.asnaghi@...com>
To: linux-kernel@...r.kernel.org
Cc: netdev@...r.kernel.org, davem@...emloft.net,
Alessandro Rubini <rubini@...dd.com>,
Federico Vaga <federico.vaga@...il.com>
Subject: [PATCH 2/3] drivers/net/most: add MediaLB driver for sta2x11
See the lkml message "[PATCH 0/3] MOST network protocol" sent on Jun
10th 2013 about this code and the missing "Signed-off" lines.
---
drivers/net/Makefile | 1 +
drivers/net/most/Kconfig | 10 +
drivers/net/most/Makefile | 6 +
drivers/net/most/sta2x11mlb.c | 1181 +++++++++++++++++++++++++++++++++++++++++
drivers/net/most/sta2x11mlb.h | 275 ++++++++++
5 files changed, 1473 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/most/Kconfig
create mode 100644 drivers/net/most/Makefile
create mode 100644 drivers/net/most/sta2x11mlb.c
create mode 100644 drivers/net/most/sta2x11mlb.h
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index ef3d090..0604d16 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_FDDI) += fddi/
obj-$(CONFIG_HIPPI) += hippi/
obj-$(CONFIG_HAMRADIO) += hamradio/
obj-$(CONFIG_IRDA) += irda/
+obj-$(CONFIG_MOST) += most/
obj-$(CONFIG_PLIP) += plip/
obj-$(CONFIG_PPP) += ppp/
obj-$(CONFIG_PPP_ASYNC) += ppp/
diff --git a/drivers/net/most/Kconfig b/drivers/net/most/Kconfig
new file mode 100644
index 0000000..cc64e4e
--- /dev/null
+++ b/drivers/net/most/Kconfig
@@ -0,0 +1,10 @@
+menu "MOST Device Drivers"
+ depends on MOST
+
+config MOST_STA2X11_MLB
+ tristate "The STA2X11 MOST block"
+ depends on MOST && STA2X11
+ ---help---
+ Adds support for MLB on the sta2x11
+
+endmenu
diff --git a/drivers/net/most/Makefile b/drivers/net/most/Makefile
new file mode 100644
index 0000000..8729533
--- /dev/null
+++ b/drivers/net/most/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the Linux Media Oriented Systems Transport drivers.
+#
+
+obj-$(CONFIG_MOST_TIMB_MLB) += timbmlb.o
+obj-$(CONFIG_MOST_STA2X11_MLB) += sta2x11mlb.o
diff --git a/drivers/net/most/sta2x11mlb.c b/drivers/net/most/sta2x11mlb.c
new file mode 100644
index 0000000..2e4b6b2
--- /dev/null
+++ b/drivers/net/most/sta2x11mlb.c
@@ -0,0 +1,1181 @@
+/*
+ * sta2x11mlb.c Driver for the sta2x11 MLB block
+ * Copyright (c) 2010-2011 Wind River
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/sta2x11-mfd.h>
+#include <net/most/most.h>
+
+#include "sta2x11mlb.h"
+
+
+static int ehcid;
+module_param(ehcid, int, S_IRUGO);
+
+static int speed = DCCR_MCS_512FS;
+module_param(speed, int, S_IRUGO);
+
+static int syncc = 8;
+module_param(syncc, int, S_IRUGO);
+
+static int syncb = 64;
+module_param(syncb, int, S_IRUGO);
+
+#define debug_reg(_reg) \
+{ \
+ .name = __stringify(_reg), \
+ .offset = _reg, \
+}
+
+static const struct debugfs_reg32 sta2x11_mlb_regs[] = {
+ debug_reg(MLB_DCCR),
+ debug_reg(MLB_SSCR),
+ debug_reg(MLB_SMCR),
+ debug_reg(MLB_VCCR),
+ debug_reg(MLB_SBCR),
+ debug_reg(MLB_ABCR),
+ debug_reg(MLB_CBCR),
+ debug_reg(MLB_IBCR),
+ debug_reg(MLB_CICR),
+
+ debug_reg(MLB_CECR(0)),
+ debug_reg(MLB_CSCR(0)),
+ debug_reg(MLB_CNBCR(0)),
+ debug_reg(MLB_LCBCR(0)),
+
+ debug_reg(MLB_CECR(1)),
+ debug_reg(MLB_CSCR(1)),
+ debug_reg(MLB_CNBCR(1)),
+ debug_reg(MLB_LCBCR(1)),
+
+ debug_reg(MLB_CECR(2)),
+ debug_reg(MLB_CSCR(2)),
+ debug_reg(MLB_CNBCR(2)),
+ debug_reg(MLB_LCBCR(2)),
+
+ debug_reg(MLB_CECR(3)),
+ debug_reg(MLB_CSCR(3)),
+ debug_reg(MLB_CNBCR(3)),
+ debug_reg(MLB_LCBCR(3)),
+};
+
+/**
+ * sta2x11_mlb_write - write directly to hardware register
+ * @dev: structure containing hardware address
+ * @reg: register offset
+ * @val: value to be written
+ *
+ * write a 32 bit value into a register
+ */
+static void sta2x11_mlb_write(struct sta2x11_mlb *dev, u32 reg, u32 val)
+{
+ writel(val, dev->base + reg);
+}
+
+/**
+ * sta2x11_mlb_read - read directly from hardware register
+ * @dev: structure containing hardware address
+ * @reg: register offset
+ *
+ * read a 32 bit value into from register
+ * return value: register contents
+ */
+static u32 sta2x11_mlb_read(struct sta2x11_mlb *dev, u32 reg)
+{
+ return readl(dev->base + reg);
+}
+
+/**
+ * sta2x11_mlb_reset - reset MLB interface
+ * @dev: structure containing hardware address
+ *
+ * The device is reset and a busy wait is done until it is ready. If the
+ * reset takes more than 1000 cycle, probably there is an the hardware failure
+ */
+static void sta2x11_mlb_reset(struct sta2x11_mlb *dev)
+{
+ int i = 1000;
+
+ sta2x11_mlb_write(dev, MLB_DCCR, DCCR_MRS_BIT);
+ while ((sta2x11_mlb_read(dev, MLB_DCCR) & DCCR_MRS_BIT) && i > 0)
+ i--;
+ if (!i)
+ dev_err(dev->mdev->parent, "failed to reset MLB\n");
+}
+
+/**
+ * skip_next - read and discard data
+ * @dev: structure containing hardware address
+ * @ch: number of channel
+ * @status: contains updated channel status
+ *
+ * read until buffer is empty or the beginning of a new packet.
+ *
+ * return value: first word of new packet, undefined if no new packet.
+ */
+static int sta2x11_mlb_skip_next(struct sta2x11_mlb *dev, u8 ch, int *status)
+{
+ int word = 0;
+
+ while(1) {
+ *status = sta2x11_mlb_read(dev, MLB_CSCR(ch));
+ if (*status & (CSCR_BM_BIT |CSCR_MRPS_BIT))
+ return word;
+ sta2x11_mlb_write(dev, MLB_CSCR(ch), *status & 0xffff);
+ word = sta2x11_mlb_read(dev, MLB_CCBCR(ch));
+ }
+}
+
+/**
+ * sta2x11_mlb_rx_sync - receive from one channel of type CHAN_SYNC
+ *
+ * @dev: sta2x11_mlb instance to use
+ * @skb: buffer where store data
+ * @skb_size: number of bytes to read
+ * @ch: channel number
+ */
+static void sta2x11_mlb_rx_sync(struct sta2x11_mlb *dev, struct sk_buff *skb, int skb_size, u8 ch)
+{
+ u32 status;
+ u32 *data;
+
+ status = sta2x11_mlb_read(dev, MLB_CSCR(ch));
+ while ((skb->len < skb_size) && !(status & CSCR_BM_BIT)) {
+ data = (u32 *)skb_put(skb, sizeof(*data));
+ *data = sta2x11_mlb_read(dev, MLB_CCBCR(ch));
+ status = sta2x11_mlb_read(dev, MLB_CSCR(ch));
+ }
+}
+
+/**
+ * sta2x11_mlb_rx_ctl_async - receive from one channel of type ASYNC or CTL
+ *
+ * @dev: sta2x11_mlb instance to use
+ * @skb: buffer where store data
+ * @skb_size: number of bytes to read
+ * @ch: channel number
+ *
+ * return value: 0 if no error occurs, -EBUSY if buffer is empty
+ */
+static int sta2x11_mlb_rx_ctl_async(struct sta2x11_mlb *dev,
+ struct sk_buff *skb, int skb_size, u8 ch)
+{
+ struct sta2x11_mlb_chan *chn = &dev->channels[ch];
+ u32 status;
+ u32 *data;
+ int word;
+ int len;
+
+ while (1) {
+ status = sta2x11_mlb_read(dev, MLB_CSCR(ch));
+ sta2x11_mlb_write(dev, MLB_CSCR(ch), status & 0xffff);
+ if (status & CSCR_REC_ERR) {
+ pr_info("MLB: rec. error %x\n", status);
+ chn->len = 0;
+ word = sta2x11_mlb_skip_next(dev, ch, &status);
+ if (status & CSCR_MRPS_BIT)
+ goto newword;
+ }
+ if (status & CSCR_BM_BIT) {
+ /* The buffer is empty, nothing to do */
+ return -EBUSY; /* FIXME better error code */
+ }
+ word = sta2x11_mlb_read(dev, MLB_CCBCR(ch));
+newword:
+ if (!chn->len)
+ chn->len = ntohs(word) + 2;
+ if (chn->len > skb_size) {
+ pr_info("MLB: len. error %d\n", chn->len);
+ chn->len = 0;
+ word = sta2x11_mlb_skip_next(dev, ch, &status);
+ if (status & CSCR_MRPS_BIT)
+ goto newword;
+ continue;
+ }
+ len = chn->len - skb->len;
+ if (len > sizeof(word))
+ len = sizeof(word);
+ data = (u32 *) skb_put(skb, len);
+ *data = word;
+ if (skb->len >= chn->len)
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * __sta2x11_mlb_rx - receive from one channel
+ * @dev: structure containing all information
+ * @ch: channel number
+ *
+ * read data from one channel and deliver to MOST layer if complete
+ * get new buffer from MOST layer if there is none in use.
+ * in case of an error discard data, no message to MOST layer.
+ */
+static void sta2x11_mlb_rx(struct sta2x11_mlb *dev, u8 ch)
+{
+ unsigned long flags;
+ int skb_size, ret;
+ struct sta2x11_mlb_chan *chn;
+ struct sk_buff *skb;
+
+ chn = &dev->channels[ch];
+ switch (chn->type) {
+ case CHAN_CTL:
+ skb_size = CTRL_FRAME_SIZE;
+ break;
+ case CHAN_ASYNC:
+ skb_size = MLB_MAX_BUF;
+ break;
+ case CHAN_SYNC:
+ skb_size = SYNC_FRAME_SIZE;
+ break;
+ default:
+ return;
+ break;
+ }
+ if (!spin_trylock_irqsave(&dev->lock, flags))
+ return;
+ skb = chn->skb;
+ if (!skb) {
+ chn->len = 0;
+ skb = most_skb_alloc(skb_size, GFP_ATOMIC);
+ chn->skb = skb;
+ if (!skb)
+ goto out;
+ }
+
+ if (chn->type == CHAN_SYNC) {
+ sta2x11_mlb_rx_sync(dev, skb, skb_size, ch);
+ } else {
+ ret = sta2x11_mlb_rx_ctl_async(dev, skb, skb_size, ch);
+ if (ret)
+ goto out;
+ }
+
+ chn->skb = NULL;
+ chn->len = 0;
+ spin_unlock_irqrestore(&dev->lock, flags);
+ /* deliver SKB upstreams */
+ skb->dev = (void *)dev->mdev;
+ most_cb(skb)->channel_type = chn->type;
+ most_cb(skb)->channel = chn->chan;
+
+ most_recv_frame(skb);
+
+out:
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/**
+ * __sta2x11_mlb_tx - transmit one buffer
+ * @dev: structure containing all information
+ * @ch: channel number
+ *
+ * get one buffer from MOST layer and transmit it.
+ * release buffer if transmission is complete.
+ *
+ * return value: 0, transmission was attempted
+ *
+ * 1, no buffer is to be transmitted
+ */
+static int sta2x11_mlb_tx(struct sta2x11_mlb *dev, u8 ch)
+{
+ unsigned long flags;
+ struct sk_buff *skb;
+ struct sta2x11_mlb_chan *chn;
+ int status;
+ int len;
+ u32 word;
+ int i;
+
+ /* check if we have sync */
+ if (dev->mlb_lock == MLB_UNLOCKED)
+ return 0;
+
+ if (!spin_trylock_irqsave(&dev->lock, flags))
+ return 0;
+ chn = &dev->channels[ch];
+ skb = chn->skb;
+ if (!skb) {
+ skb = skb_dequeue(&chn->data_q);
+ if (!skb) {
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 1;
+ }
+ chn->skb = skb;
+ chn->pos = 0;
+ }
+ status = 0;
+ status = sta2x11_mlb_read(dev, MLB_CSCR(ch));
+ for (i = chn->pos; i < skb->len; i += 4) {
+
+ status = sta2x11_mlb_read(dev, MLB_CSCR(ch));
+ if (status & CSCR_REC_ERR) {
+ sta2x11_mlb_write(dev, MLB_CSCR(ch), status & 0xffff);
+ dev_err(&dev->pdev->dev, "MLB: tx state, pos: %x, %d\n",
+ status, i);
+ status = sta2x11_mlb_read(dev, MLB_CSCR(ch));
+ if (status & CSCR_REC_ERR) {
+ dev_err(&dev->pdev->dev,
+ "MLB: tx2state, pos: %x, %d\n",
+ status, i);
+ kfree_skb(skb);
+ chn->skb = NULL;
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ }
+ if (status & CSCR_BF_BIT) {
+ chn->pos = i;
+ break;
+ }
+ len = skb->len - i;
+ if (len < sizeof(u32)) {
+ word = 0;
+ memcpy(&word, skb->data + i, len);
+ sta2x11_mlb_write(dev, MLB_CNBCR(ch), word);
+ } else
+ sta2x11_mlb_write(dev, MLB_CNBCR(ch),
+ *(u32 *) (skb->data + i));
+ }
+
+ sta2x11_mlb_write(dev, MLB_CSCR(ch), status & 0xffff);
+ if (i >= skb->len) {
+ kfree_skb(skb);
+ chn->skb = NULL;
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+ }
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+}
+
+/**
+ * __config_channel - set hardware depending on information from higher layer
+ * @dev: structure containing all information
+ * @ch: channel number
+ *
+ * The parameters for one channel are set.
+ * return value: 0, no error
+ *
+ * -EINVAL, some parameter error, check kernel log.
+ */
+static int sta2x11_mlb_config_channel(struct sta2x11_mlb *dev, u8 ch)
+{
+ u32 val;
+ u32 mode;
+ int sta2x11_mlb_type;
+ struct sta2x11_mlb_chan *chn;
+
+ chn = &dev->channels[ch];
+ chn->pos = 0;
+ chn->len = 0;
+ chn->skb = NULL;
+ mode = MLB_IO;
+ chn->mode = mode;
+
+ val = 0;
+ val |= CECR_CE_BIT;
+ switch (chn->dir) {
+ case MLB_READ:
+ break;
+ case MLB_WRITE:
+ val |= CECR_TR_BIT;
+ break;
+ default:
+ dev_err(dev->mdev->parent, "unknown direction %d\n", chn->dir);
+ return -EINVAL;
+ break;
+ }
+
+ /* channel type (synchronous, isochronous, asyn, control) */
+ switch (chn->type) {
+ case CHAN_CTL:
+ sta2x11_mlb_type = CECR_CT_CTRL;
+ break;
+ case CHAN_SYNC:
+ sta2x11_mlb_type = CECR_CT_SYNC;
+ break;
+ case CHAN_ASYNC:
+ sta2x11_mlb_type = CECR_CT_ASYN;
+ break;
+ default:
+ dev_err(dev->mdev->parent, "unknown type %d\n", chn->type);
+ return -EINVAL;
+ break;
+ }
+ val |= sta2x11_mlb_type << CECR_CT_SHIFT;
+
+ /* setup mode */
+ switch (mode) {
+ case MLB_DMA:
+ val |= (CECR_MDS_DMAPP << CECR_MDS_SHIFT);
+ break;
+ case MLB_IO:
+ val |= (CECR_MDS_IO << CECR_MDS_SHIFT);
+ val |= CECR_MTSR_BIT;
+ break;
+ default:
+ dev_err(dev->mdev->parent, "unknown mode %d\n", mode);
+ return -EINVAL;
+ break;
+ }
+
+ /* channel address */
+ val |= (chn->chan >> 1) << CECR_CA_SHIFT;
+ chn->initialized = 1;
+ sta2x11_mlb_write(dev, MLB_CECR(ch), val);
+ return 0;
+}
+
+/**
+ * sta2x11_mlb_serve_interrupt - handles channel interrupt
+ * @dev: the device instance
+ * @ch: channel number that raise an interrupt
+ */
+static void sta2x11_mlb_serve_interrupt(struct sta2x11_mlb *dev, u8 ch) {
+ struct sta2x11_mlb_chan *chn;
+ int ret, status;
+ u32 val;
+
+ chn = &dev->channels[ch];
+ if (unlikely(!chn->initialized)) {
+ dev_info(&dev->pdev->dev,
+ "non-initialized channel %d\n", ch);
+ return;
+ }
+ switch (chn->dir) {
+ case MLB_READ:
+ sta2x11_mlb_rx(dev, ch);
+ break;
+ case MLB_WRITE:
+ status = sta2x11_mlb_read(dev, MLB_CSCR(ch));
+ if (status & CSCR_REC_ERR) {
+ val = status & 0xffff;
+ sta2x11_mlb_write(dev, MLB_CSCR(ch), val);
+ dev_err(&dev->pdev->dev,
+ "MLB: tx ir state %x\n",
+ status);
+ }
+
+ ret = sta2x11_mlb_tx(dev, ch);
+ if (ret) {
+ val = sta2x11_mlb_read(dev, MLB_CECR(ch));
+ val |= CECR_MTSR_BIT;
+ sta2x11_mlb_write(dev, MLB_CECR(ch), val);
+ }
+ break;
+ }
+
+}
+
+/**
+ * sta2x11_mlb_interrupt - Handles mlb interrupts
+ * @irq: unused, only one interrupt numer used
+ * @_dev: pointer to dev structure
+ *
+ * all channels are checked, if possible data transfer is done.
+ * MLB and MOSt status is updated.
+ * return value: IRQ_NONE, nothing done, interrupte was not for us
+ *
+ * IRQ_HANDLED, otherwise
+ */
+static irqreturn_t sta2x11_mlb_interrupt(int irq, void *_dev)
+{
+ int i;
+ int irq_redo_cnt = 0;
+ struct sta2x11_mlb *dev = _dev;
+ u32 pending;
+ int handled = 0;
+ int sscr;
+
+ sscr = sta2x11_mlb_read(dev, MLB_SSCR);
+ sscr &= SSCR_SDMU_BIT | SSCR_SDML_BIT | SSCR_SDSC_BIT |
+ SSCR_SDCS_BIT | SSCR_SDNU_BIT | SSCR_SDNL_BIT | SSCR_SDR_BIT;
+ if (sscr != 0) {
+ if (sscr & SSCR_SDNU_BIT)
+ dev->net_lock = MLB_UNLOCKED;
+ if (sscr & SSCR_SDNL_BIT)
+ dev->net_lock = MLB_LOCKED;
+ if (sscr & SSCR_SDMU_BIT)
+ dev->mlb_lock = MLB_UNLOCKED;
+ if (sscr & SSCR_SDML_BIT)
+ dev->mlb_lock = MLB_LOCKED;
+ sta2x11_mlb_write(dev, MLB_SSCR, sscr);
+ handled = 1;
+ }
+
+ while ((pending = sta2x11_mlb_read(dev, MLB_CICR))) {
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ if (!(pending & (1 << i)))
+ continue; /* nothing to do */
+ sta2x11_mlb_serve_interrupt(dev, i);
+ handled = 1;
+ }
+
+ if (irq_redo_cnt++ > 5)
+ dev_warn(&dev->pdev->dev, "Possible interrupt loop");
+ }
+
+ return IRQ_RETVAL(handled);
+}
+
+/**
+ * reset_all_chans - turn off all channels
+ * @dev: structure containing hardware address
+ *
+ * all channels are turned off.
+ */
+static void sta2x11_mlb_reset_all_chans(struct sta2x11_mlb *dev)
+{
+ u8 ch;
+ for (ch = 0; ch < MAX_CHANNELS; ch++)
+ sta2x11_mlb_write(dev, MLB_CECR(ch), 0);
+}
+
+/**
+ * config_mlb - set parameter common to all channels
+ * @dev: structure containing hardware address
+ *
+ * set speed, host id and endianness
+ *
+ * return value : 0, always successful.
+ */
+static int sta2x11_mlb_config_mlb(struct sta2x11_mlb *dev)
+{
+ u32 dccr = 0;
+
+ sta2x11_mlb_reset(dev);
+ sta2x11_mlb_reset_all_chans(dev);
+
+ /* allow all system interrupts */
+ sta2x11_mlb_write(dev, MLB_SMCR, 0);
+ dccr = (MLB_DEV_ADDRESS(ehcid) >> 1) << DCCR_MDA_SHIFT;
+ dccr |= (speed << DCCR_MCS_SHIFT) | MLB_LE_ENABLE | DCCR_MDE_BIT;
+ sta2x11_mlb_write(dev, MLB_DCCR, dccr);
+ return 0;
+}
+
+/**
+ * poll_func - check if channels are ready
+ * @data: point to dev
+ *
+ * check all active channel if data can be transferred.
+ * restart timer.
+ */
+static void sta2x11_mlb_poll_func(unsigned long data)
+{
+ struct sta2x11_mlb *dev;
+ u32 val;
+ int i;
+
+ dev = (struct sta2x11_mlb *)data;
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ if (!(dev->active_channels & (1 << i)))
+ continue; /* Skip un-active */
+
+ switch (dev->channels[i].dir) {
+ case MLB_READ:
+ val = sta2x11_mlb_read(dev, MLB_CSCR(i));
+ if (!(val & CSCR_BM_BIT))
+ sta2x11_mlb_rx(dev, i);
+ break;
+ case MLB_WRITE:
+ sta2x11_mlb_tx(dev, i);
+ break;
+ }
+ }
+ mod_timer(&dev->poll_timer, jiffies + 1);
+}
+
+/**
+ * get_chan - get next free channel number depending on type
+ * @dev: structure containing all information
+ * @type: type of channel SYNC or not SYNC.
+ *
+ *
+ * SYNC channels have a reserved number range, in order to use the
+ * larger buffers.
+ *
+ * return value: channel number, if a channel is free
+ *
+ * -ENODEV, else
+ */
+static int sta2x11_mlb_get_chan(struct sta2x11_mlb *dev, enum most_chan_type type)
+{
+ int i;
+ int start_chan;
+ int end_chan;
+
+ if (type == CHAN_SYNC) {
+ start_chan = MAX_CHANNELS - syncc;
+ end_chan = MAX_CHANNELS;
+ } else {
+ start_chan = 0;
+ end_chan = MAX_CHANNELS - syncc;
+ }
+ for (i = start_chan; i < end_chan; i++) {
+ if (!(dev->active_channels & (1 << i))) {
+ dev->active_channels |= 1 << i;
+ return i;
+ }
+ }
+ return -ENODEV;
+}
+
+/**
+ * free_chan - free channel in list
+ * @dev: structure containing all information
+ * @channel: channel to be freed
+ *
+ * Channel is marked as free. No checks are done.
+ */
+static void sta2x11_mlb_free_chan(struct sta2x11_mlb *dev, int channel)
+{
+ dev->active_channels &= ~(1 << channel);
+}
+
+/**
+ * sta2x11_mlb_conf_channel - setup a single channel
+ * @mdev: struct from socket layer
+ * @type: type of channel
+ * @channel: number of channel
+ * @flags: up or down
+ *
+ * in case of shutdown read all pending data.
+ */
+static int sta2x11_mlb_conf_channel(struct most_dev *mdev,
+ enum most_chan_type type,
+ u8 channel, u8 flags)
+{
+ struct sta2x11_mlb *dev = (struct sta2x11_mlb *)mdev->driver_data;
+ unsigned long irq_flags;
+ struct sta2x11_mlb_chan *chn;
+ int err = -EINVAL;
+ int ch;
+ u32 val;
+
+ dev_dbg(mdev->parent, "%s: channel: %d, flags: %x\n",
+ __func__, channel, flags);
+
+ if (!channel || (channel & 0x1) || (channel > MAX_LCHAN))
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->lock, irq_flags);
+ if (flags & MOST_CONF_FLAG_UP) {
+
+
+ ch = sta2x11_mlb_get_chan(dev, type);
+ if (ch < 0)
+ goto out;
+ dev->chantab[channel >> 1] = ch;
+ chn = &dev->channels[ch];
+ chn->chan = channel;
+ chn->type = type;
+ chn->dir = (flags & MOST_CONF_FLAG_TX) ? MLB_WRITE : MLB_READ;
+ err = sta2x11_mlb_config_channel(dev, ch);
+
+ } else {
+ ch = dev->chantab[channel >> 1];
+ if (ch < 0 || ch > MAX_CHANNELS)
+ goto out;
+
+ chn = &dev->channels[ch];
+
+ if (chn->dir == MLB_READ) {
+ /* disable interrupts and channel */
+ val = CECR_MLFS_BIT | CECR_MBER_BIT | CECR_MTSR_BIT;
+ val |= CECR_MRSR_BIT | CECR_MDBR_BIT | CECR_MPRO_BIT;
+ sta2x11_mlb_write(dev, MLB_CECR(ch), val);
+
+ while (!(sta2x11_mlb_read(dev, MLB_CSCR(ch)) & CSCR_BM_BIT))
+ sta2x11_mlb_read(dev, MLB_CCBCR(ch));
+ } else {
+ /* only disable interrupts */
+ val = sta2x11_mlb_read(dev, MLB_CECR(ch));
+ val |= CECR_MLFS_BIT | CECR_MBER_BIT | CECR_MTSR_BIT;
+ val |= CECR_MRSR_BIT | CECR_MDBR_BIT | CECR_MPRO_BIT;
+ sta2x11_mlb_write(dev, MLB_CECR(ch), val);
+ }
+ sta2x11_mlb_free_chan(dev, ch);
+ dev->chantab[channel >> 1] = -1;
+ chn->chan = 0;
+ chn->initialized = 0;
+ err = 0;
+ }
+out:
+ spin_unlock_irqrestore(&dev->lock, irq_flags);
+ return err;
+}
+
+static void sta2x11_mlb_set_lcbcr(struct sta2x11_mlb *dev,
+ u8 ch, int pos, int size)
+{
+ u32 val;
+
+ val = ((10 / 2) << LCBCR_TH_SHIFT);
+ val |= ((size / 4 - 1) << LCBCR_BD_SHIFT);
+ val |= (pos / 4 << LCBCR_SA_SHIFT);
+ sta2x11_mlb_write(dev, MLB_LCBCR(ch), val);
+}
+/**
+ * sta2x11_mlb_open - open device
+ * @mdev: MOST layer data containg pointer to dev
+ *
+ * open the device. This is done once for all channels.
+ * setup internal buffers.
+ * Wait for device to become ready.
+ * Initialize timer.
+ * return value: 0, no error.
+ *
+ * -EINVAL, device is not ready
+ *
+ * else, configuration error
+ */
+static int sta2x11_mlb_open(struct most_dev *mdev)
+{
+ struct sta2x11_mlb *dev = (struct sta2x11_mlb *)mdev->driver_data;
+ int i;
+ int rc;
+ u8 ch;
+ int async_size;
+ int buf_pos;
+ u32 val;
+
+ rc = sta2x11_mlb_config_mlb(dev);
+ if (rc < 0)
+ return rc;
+
+ syncb &= ~3;
+ async_size = (INTRAM - (syncc * syncb)) / (MAX_CHANNELS - syncc);
+ async_size &= ~3;
+ buf_pos = 0;
+ for (ch = 0; ch < MAX_CHANNELS - syncc; ch++) {
+ int size = ((ch < MAX_CHANNELS - syncc) ? async_size : syncb);
+ sta2x11_mlb_set_lcbcr(dev, ch, buf_pos, size);
+ buf_pos += size;
+ }
+
+ dev->active_channels = 0;
+ i = 50;
+ while ((dev->mlb_lock == MLB_UNLOCKED) && (i-- > 0))
+ msleep_interruptible(1);
+ if (i <= 0)
+ return -EINVAL;
+ for (i = 0; i < (MAX_LCHAN >> 1); i++)
+ dev->chantab[i] = -1;
+ for (i = 0; i < MAX_CHANNELS; i++) {
+ val = sta2x11_mlb_read(dev, MLB_CSCR(i)) & 0xffff;
+ sta2x11_mlb_write(dev, MLB_CSCR(i), val);
+ skb_queue_head_init(&dev->channels[i].data_q);
+ }
+
+ setup_timer(&dev->poll_timer,
+ sta2x11_mlb_poll_func, (unsigned long)dev);
+ dev->poll_timer.expires = jiffies + 1;
+ add_timer(&dev->poll_timer);
+ dev->opened = 1;
+ return rc;
+}
+
+/**
+ * sta2x11_mlb_close - close all channels
+ * @mdev: device information from socket layer
+ *
+ * remove all pending buffers.
+ * remove timer.
+ *
+ * return value: 0, always successful
+ */
+static int sta2x11_mlb_close(struct most_dev *mdev)
+{
+ struct sta2x11_mlb *dev = (struct sta2x11_mlb *)mdev->driver_data;
+ int i;
+
+ dev->active_channels = 0;
+
+ if (!dev->opened)
+ return 0;
+
+ dev->opened = 0;
+ del_timer_sync(&dev->poll_timer);
+ for (i = 0; i < MAX_CHANNELS; i++)
+ skb_queue_purge(&dev->channels[i].data_q);
+
+ return 0;
+}
+
+/**
+ * sta2x11_mlb_send - send one buffer
+ * @skb: buffer from MOST layer
+ *
+ * send one buffer, data is queued.
+ *
+ * return value: 0, no error
+ *
+ * -EINVAL, device not opened, illegal channel type or wrong channel number
+ */
+static int sta2x11_mlb_send(struct sk_buff *skb)
+{
+ struct most_dev *mdev = (struct most_dev *)skb->dev;
+ struct sta2x11_mlb *dev = (struct sta2x11_mlb *)mdev->driver_data;
+ u32 val;
+ u8 channel;
+ u8 ch;
+
+ if (!dev->opened)
+ return -EINVAL;
+ channel = most_cb(skb)->channel;
+ if (!channel || (channel & 0x1) || (channel > MAX_LCHAN)) {
+ dev_warn(&dev->pdev->dev,"%s: Got illegal channel: %d\n",
+ __func__, most_cb(skb)->channel);
+ return -EINVAL;
+ }
+ ch = dev->chantab[channel >> 1];
+ if (ch >= MAX_CHANNELS)
+ return -EINVAL;
+ switch (most_cb(skb)->channel_type) {
+ case CHAN_SYNC:
+ skb_queue_tail(&dev->channels[ch].data_q, skb);
+ sta2x11_mlb_tx(dev, ch);
+ val = sta2x11_mlb_read(dev, MLB_CECR(ch)) & ~CECR_MTSR_BIT;
+ sta2x11_mlb_write(dev, MLB_CECR(ch), val);
+ break;
+ case CHAN_CTL:
+ case CHAN_ASYNC:
+ skb_queue_tail(&dev->channels[ch].data_q, skb);
+ sta2x11_mlb_tx(dev, ch);
+ break;
+ default:
+ dev_warn(&dev->pdev->dev,
+ "%s: Got unsupported channel type: %d\n",
+ __func__, most_cb(skb)->channel_type);
+ kfree_skb(skb);
+ return -EINVAL;
+ break;
+ }
+ return 0;
+}
+
+/**
+ * configure - configure the PCI device
+ * @pdev: PCI device
+ *
+ * enable and configure device.
+ * return value: 0, no error
+ *
+ * -1, region could not be mapped or interrupt not available
+ */
+static int sta2x11_mlb_configure(struct pci_dev *pdev)
+{
+ struct sta2x11_mlb *dev;
+ int ret;
+ void __iomem * const *piot;
+
+ dev = (struct sta2x11_mlb *)pci_get_drvdata(pdev);
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable device\n");
+ goto no_enable;
+ }
+
+ /* request all memory regions associated with this device */
+
+ ret = pcim_iomap_regions(pdev, BAR_MASK, KBUILD_MODNAME);
+ if (ret)
+ goto no_ioremap;
+ piot = pcim_iomap_table(pdev);
+ if (piot)
+ dev->base = piot[BAR];
+
+ pci_set_master(pdev);
+ pci_enable_msi(pdev);
+
+ dev_dbg(&pdev->dev, "requesting irq %d\n", pdev->irq);
+ ret = request_irq(pdev->irq, sta2x11_mlb_interrupt, IRQF_SHARED,
+ KBUILD_MODNAME, dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to allocate IRQ %d\n", pdev->irq);
+ goto no_irq;
+ }
+ dev_dbg(&pdev->dev, "configured ok\n");
+
+ return 0;
+
+no_irq:
+ dev_dbg(&pdev->dev, "unmapping io\n");
+ pcim_iounmap_regions(pdev, BAR_MASK);
+no_ioremap:
+ pci_disable_device(pdev);
+no_enable:
+ return ret;
+}
+
+/**
+ * unconfigure - release PCI device
+ * @pdev: PCI device
+ *
+ * release device at PCI level and free local data.
+ * free interrupt.
+ * unmap regions.
+ * unregister at MOST socker layer
+ */
+static void sta2x11_mlb_unconfigure(struct pci_dev *pdev)
+{
+ struct sta2x11_mlb *dev;
+
+ dev = pci_get_drvdata(pdev);
+
+ if (dev->base) {
+ sta2x11_mlb_reset_all_chans(dev);
+ sta2x11_mlb_write(dev, MLB_DCCR, 0);
+ dev_dbg(&pdev->dev, "unmap io @%p\n", dev->base);
+ }
+
+
+ free_irq(pdev->irq, dev);
+
+ pcim_iounmap_regions(pdev, BAR_MASK);
+ pci_disable_msi(pdev);
+ pci_disable_device(pdev);
+ kfree(dev);
+}
+
+/**
+ * probe - check if device is present and allocate data structures
+ * @pcidev: PCI device
+ * @id: not used
+ *
+ * initialize local data.
+ * check module parameters here.
+ * register at MOST socket layer.
+ *
+ * return value: 0, no error
+ *
+ * -ENOMEM, no memory for internal structures.
+ *
+ * other, errno defining cause
+ */
+static int sta2x11_mlb_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct sta2x11_mlb *dev;
+ int err = 0;
+
+ if (ehcid < 0 || ehcid > 3) {
+ dev_err(&pdev->dev, "invalid ehcid value %d\n", ehcid);
+ return -EINVAL;
+ }
+ if (speed < DCCR_MCS_256FS || speed > DCCR_MCS_1024FS) {
+ dev_err(&pdev->dev, "invalid speed grade %d\n", speed);
+ return -EINVAL;
+ }
+ if (syncc < 0 || syncc > MAX_CHANNELS - 2) {
+ dev_err(&pdev->dev, "invalid syncc value %d\n", syncc);
+ return -EINVAL;
+ }
+ if (syncb < 32 || syncb > 256) {
+ dev_err(&pdev->dev, "invalid syncb size %d\n", syncb);
+ return -EINVAL;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->mdev = most_alloc_dev();
+ if (!dev->mdev) {
+ err = -ENOMEM;
+ goto err_alloc_dev;
+ }
+
+ dev->pdev = pdev;
+ dev->mdev->owner = THIS_MODULE;
+ dev->mdev->driver_data = dev;
+ dev->mdev->parent = &pdev->dev;
+ dev->mdev->open = sta2x11_mlb_open;
+ dev->mdev->close = sta2x11_mlb_close;
+ dev->mdev->send = sta2x11_mlb_send;
+ dev->mdev->conf_channel = sta2x11_mlb_conf_channel;
+
+ dev->mlb_lock = MLB_UNLOCKED;
+ dev->net_lock = MLB_UNLOCKED;
+ dev->active_channels = 0;
+ dev->opened = 0;
+ dev->disabled = 0;
+
+ spin_lock_init(&dev->lock);
+
+ pci_set_drvdata(pdev, dev);
+
+ err = sta2x11_mlb_configure(pdev);
+ if (err)
+ goto err_configure;
+
+ /* register to the MOST layer */
+ err = most_register_dev(dev->mdev);
+ if (err)
+ goto err_register;
+
+ dev_dbg(&pdev->dev, "most devname <%s>\n", dev->mdev->name);
+
+ dev->regset = kmalloc(sizeof(struct debugfs_regset32), GFP_KERNEL);
+ if (dev->regset) {
+ dev->regset->regs = sta2x11_mlb_regs;
+ dev->regset->nregs = ARRAY_SIZE(sta2x11_mlb_regs);
+ dev->regset->base = dev->base;
+ dev->dentry = debugfs_create_regset32("registers", S_IRUGO,
+ NULL, dev->regset);
+ if (IS_ERR(dev->dentry)) {
+ dev_dbg(&dev->pdev->dev, "failed to register debugfs\n");
+ }
+ }
+ return 0;
+
+err_register:
+ sta2x11_mlb_unconfigure(pdev);
+err_configure:
+ most_free_dev(dev->mdev);
+err_alloc_dev:
+ kfree(dev);
+ return err;
+}
+
+/**
+ * remove - unconfigure device
+ * @pcidev: PCI device
+ *
+ * The device is set to a state before initialization.
+ * All resources are freed.
+ */
+static void sta2x11_mlb_remove(struct pci_dev *pdev)
+{
+ struct sta2x11_mlb *dev = pci_get_drvdata(pdev);
+
+ if (dev->regset) {
+ if (!IS_ERR_OR_NULL(dev->dentry)) {
+ debugfs_remove(dev->dentry);
+ }
+ kfree(dev->regset);
+ }
+
+ most_unregister_dev(dev->mdev);
+ sta2x11_mlb_unconfigure(pdev);
+ most_free_dev(dev->mdev);
+ kfree(dev);
+}
+
+#ifdef CONFIG_PM
+/**
+ * suspend - suspend device
+ * @pdev: PCI device
+ * @state: new power state
+ *
+ * attempts to set device to a new power state.
+ * all data are discarded, everything has to be set up again after power up.
+ *
+ * return value: 0, always successful, even if hardware does not support
+ * power management
+ */
+static int sta2x11_mlb_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct sta2x11_mlb *dev = pci_get_drvdata(pdev);
+ int i;
+
+ if (dev->opened) {
+ del_timer(&dev->poll_timer);
+ for (i = 0; i < MAX_CHANNELS; i++)
+ skb_queue_purge(&dev->channels[i].data_q);
+ dev->opened = 0;
+ }
+ /* save pci state */
+ pci_save_state(pdev);
+ if (pci_set_power_state(pdev, pci_choose_state(pdev, state))) {
+ pci_disable_device(pdev);
+ dev->disabled = 1;
+ }
+ dev_dbg(&pdev->dev,"MLB: suspend\n");
+ return 0;
+}
+
+/**
+ * resume - set device to power on state.
+ * @pdev: PCI device
+ *
+ * set device to power on state.
+ * return value: 0, no error
+ *
+ * other, errno of error.
+ */
+static int sta2x11_mlb_resume(struct pci_dev *pdev)
+{
+ struct sta2x11_mlb *dev = pci_get_drvdata(pdev);
+ int err;
+
+ dev_dbg(&pdev->dev, "MLB: resume\n");
+ /* restore pci state */
+ if (dev->disabled) {
+ err = pci_enable_device(pdev);
+ if (err) {
+ dev_warn(&pdev->dev, "MLB: Can't enable device.\n");
+ return err;
+ }
+ dev->disabled = 0;
+ }
+ err = pci_set_power_state(pdev, PCI_D0);
+ if (err) {
+ pci_disable_device(pdev);
+ dev_warn(&pdev->dev, "MLB: Can't enable device.\n");
+ return err;
+ }
+
+ pci_restore_state(pdev);
+
+ return 0;
+}
+#endif
+
+static DEFINE_PCI_DEVICE_TABLE(ids) = {
+ {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, 0xcc12)},
+ {0,}
+};
+
+static struct pci_driver sta2x11_sta2x11_mlb_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = ids,
+ .probe = sta2x11_mlb_probe,
+ .remove = sta2x11_mlb_remove,
+#ifdef CONFIG_PM
+ .suspend = sta2x11_mlb_suspend,
+ .resume = sta2x11_mlb_resume,
+#endif
+};
+
+module_pci_driver(sta2x11_sta2x11_mlb_driver);
+
+MODULE_AUTHOR("Wind River");
+MODULE_DESCRIPTION("ConneXt MediaLB Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.3");
+MODULE_DEVICE_TABLE(pci, ids);
diff --git a/drivers/net/most/sta2x11mlb.h b/drivers/net/most/sta2x11mlb.h
new file mode 100644
index 0000000..2458ba8
--- /dev/null
+++ b/drivers/net/most/sta2x11mlb.h
@@ -0,0 +1,275 @@
+
+#ifndef STA2X11MLB_H_
+#define STA2X11MLB_H_
+
+#define BAR 0
+#define BAR_MASK 1
+
+/* size of internal RAM in "quadlets" */
+#define INTRAM 1024
+#define MAX_CHANNELS 30
+#define MAX_LCHAN 126
+
+#define MLB_DCCR 0x00
+#define MLB_SSCR 0x04
+#define MLB_SDCR 0x08
+#define MLB_SMCR 0x0c
+#define MLB_VCCR 0x1c
+#define MLB_SBCR 0x20
+#define MLB_ABCR 0x24
+#define MLB_CBCR 0x28
+#define MLB_IBCR 0x2c
+#define MLB_CICR 0x30
+
+#define MLB_CECR(n) (0x10*(n)+0x40)
+#define MLB_CSCR(n) (0x10*(n)+0x44)
+#define MLB_CCBCR(n) (0x10*(n)+0x48)
+#define MLB_CNBCR(n) (0x10*(n)+0x4c)
+#define MLB_LCBCR(n) (0x04*(n)+0x280)
+
+/* Device Control Configuration Register bit definitions
+ */
+#define DCCR_MDE_BIT (1<<31)
+#define DCCR_LBM_BIT (1<<30)
+#define DCCR_MCS_MASK 0x3
+#define DCCR_MCS_SHIFT 28
+/*bit 27 reserved */
+#define DCCR_MLK_BIT (1<<26)
+#define DCCR_MLE_BIT (1<<25)
+#define DCCR_MHRE_BIT (1<<24)
+#define DCCR_MRS_BIT (1<<23)
+/*bits 22-8 reserved */
+#define DCCR_MDA_MASK 0xff
+#define DCCR_MDA_SHIFT 0
+
+#define DCCR_MCS_256FS 0
+#define DCCR_MCS_512FS 1
+#define DCCR_MCS_1024FS 2
+
+/* System Status Configuration Register bit definitions
+ */
+#define SSCR_SSRE_BIT (1<<7)
+#define SSCR_SDMU_BIT (1<<6)
+#define SSCR_SDML_BIT (1<<5)
+#define SSCR_SDSC_BIT (1<<4)
+#define SSCR_SDCS_BIT (1<<3)
+#define SSCR_SDNU_BIT (1<<2)
+#define SSCR_SDNL_BIT (1<<1)
+#define SSCR_SDR_BIT (1<<0)
+
+/* System Mask Configuration Register bit definitions
+ */
+#define SMCR_SMMU_BIT (1<<6)
+#define SMCR_SMML_BIT (1<<5)
+#define SMCR_SMSC_BIT (1<<4)
+#define SMCR_SMCS_BIT (1<<3)
+#define SMCR_SMNU_BIT (1<<2)
+#define SMCR_SMNL_BIT (1<<1)
+#define SMCR_SMR_BIT (1<<0)
+
+/* Version Control Configuration Register (VCCR) bit definitions
+ */
+#define VCCR_UMA_MASK 0xff
+#define VCCR_UMA_SHIFT 24
+#define VCCR_UMI_MASK 0xff
+#define VCCR_UMI_SHIFT 16
+#define VCCR_MMA_MASK 0xff
+#define VCCR_MMA_SHIFT 8
+#define VCCR_MMI_MASK 0xff
+#define VCCR_MMI_SHIFT 0
+
+/* Channel n Entry Configuration Register bit definitions
+ */
+#define CECR_CE_BIT (1<<31)
+#define CECR_TR_BIT (1<<30)
+#define CECR_CT_MASK 0x3
+#define CECR_CT_SHIFT 28
+#define CECR_PCE_BIT (1<<27)
+#define CECR_FSE_BIT (1<<27)
+#define CECR_FCE_BIT (1<<27)
+#define CECR_MDS_MASK 0x3
+#define CECR_MDS_SHIFT 25
+/* bit 24 reserved */
+#define CECR_MASK_MASK 0xff /* I've already decided on the naming convention
+ * when I found this bit-field :-)
+ */
+#define CECR_MASK_SHIFT 16
+
+/* bit 23 reserved */
+#define CECR_MLFS_BIT (1<<22)
+/* bit 21 reserved */
+#define CECR_MBER_BIT (1<<20)
+#define CECR_MBST_BIT (1<<19)
+#define CECR_MTSR_BIT (1<<19)
+#define CECR_MBDO_BIT (1<<18)
+#define CECR_MRSR_BIT (1<<18)
+#define CECR_MDBR_BIT (1<<17)
+#define CECR_MPRO_BIT (1<<16)
+
+#define CECR_FSCD_BIT (1<<15)
+#define CECR_IPL_MASK 0xff
+#define CECR_IPL_SHIFT 8
+#define CECR_PCTH_MASK 0xf
+#define CECR_PCTH_SHIFT 8
+#define CECR_FSPC_MASK 0xf
+#define CECR_FSPC_SHIFT 8
+#define CECR_CA_MASK 0xff
+#define CECR_CA_SHIFT 0
+
+#define CECR_MDS_DMAPP 0
+#define CECR_MDS_DMACR 1
+#define CECR_MDS_IO 2
+
+#define CECR_CT_SYNC 0
+#define CECR_CT_ISOC 1
+#define CECR_CT_ASYN 2
+#define CECR_CT_CTRL 3
+
+/* Channel n Status Configuration Register (CSCR) bit definitions
+ */
+#define CSCR_BM_BIT (1<<31)
+#define CSCR_BF_BIT (1<<30)
+#define CSCR_IVB_MASK 0x3
+#define CSCR_IVB_SHIFT 18
+#define CSCR_GIRB_BIT (1<<17)
+#define CSCR_GB_BIT (1<<17)
+#define CSCR_RDY_BIT (1<<16)
+#define CSCR_STS_MASK 0xffff
+#define CSCR_STS_SHIFT 0
+
+#define CSCR_MRPS_BIT (1<<9)
+#define CSCR_MRPA_BIT (1<<8)
+/* bit 7 reserved */
+#define CSCR_MLFS_BIT (1<<6)
+#define CSCR_MHBE_BIT (1<<5)
+#define CSCR_MBER_BIT (1<<4)
+#define CSCR_MBST_BIT (1<<3)
+#define CSCR_MTSR_BIT (1<<3)
+#define CSCR_MBDO_BIT (1<<2)
+#define CSCR_MRSR_BIT (1<<2)
+#define CSCR_MDBR_BIT (1<<1)
+#define CSCR_MPRO_BIT (1<<0)
+
+#define CSCR_REC_ERR (CSCR_MPRO_BIT|CSCR_MDBR_BIT|CSCR_MRPA_BIT)
+/* Channel n Current Buffer Configuration Register (CCBCR) bit definitions
+ * Channel n Next Buffer Configuration Register (CNBCR) bit definitions
+ *
+ * Will be filled in later when we support DMA. in IO mode they are
+ * plain 32bit register for receive/transmit data buffer
+ */
+
+/* Local Channel n Buffer Configuration Register (LCBCR) bit definitions
+ */
+#define LCBCR_TH_MASK 0xff
+#define LCBCR_TH_SHIFT 22
+#define LCBCR_BD_MASK 0x7f
+#define LCBCR_BD_SHIFT 13
+#define LCBCR_SA_MASK 0xff
+#define LCBCR_SA_SHIFT 0
+
+/* enable little endian mode if required */
+#if defined(__LITTLE_ENDIAN)
+#define MLB_LE_ENABLE DCCR_MLE_BIT
+#else
+#if defined(__BIG_ENDIAN)
+#define MLB_LE_ENABLE 0
+#else
+#error endianness unknown
+#endif
+#endif
+
+/* 0x180 : first external host controller */
+#define MLB_DEV_ADDRESS(i) (0x180+2*(i))
+
+/* default values for INIC */
+#define FROM_INIC 2
+#define TO_INIC 4
+
+#define RXC 0
+#define TXC 1
+
+/* Direction of channel */
+enum direction {
+ MLB_READ,
+ MLB_WRITE
+};
+
+enum mode {
+ MLB_DMA,
+ MLB_IO
+};
+
+enum lock {
+ MLB_UNLOCKED,
+ MLB_LOCKED
+};
+
+#define MLB_MAX_BUF (1024*sizeof(u32))
+#define MLB_DMA_SIZE (MLB_MAX_BUF*MAX_CHANNELS)
+
+/* setting to higher value is not useful: we are transferring in real time */
+#define SYNC_FRAME_SIZE (32*sizeof(u32))
+#define CTRL_FRAME_SIZE 64
+#define ASYNC_FRAME_SIZE MLB_MAX_BUF
+
+/**
+ * struct channel - Information for one channel
+ * @initialized: tells if channel is initialized.
+ * @chan: logical channel number used on MOST layer
+ * @type: type, async, syn or control
+ * @dir: direction, read or write
+ * @mode: mode, DMA or IO
+ * @len: size of buffer
+ * @pos: current position in buffer
+ * @skb: socket buffer from MOST layer
+ * @data_q: queue for buffer handling
+ * @data: buffer, testing only
+ */
+struct sta2x11_mlb_chan {
+ int initialized;
+ u8 chan;
+ u8 type;
+ enum direction dir;
+ enum mode mode;
+ int len;
+ int pos;
+ struct sk_buff *skb;
+ struct sk_buff_head data_q;
+ u32 *data;
+};
+
+/**
+ * struct private - all data for one instance of MLB
+ * @base: hardware base address
+ * @pdev: PCI device
+ * @mdev: most device
+ * @lock: spinlock for hardware access
+ * @disabled: hardware is shutdown, or being shut down
+ * @opened: device is opened
+ * @poll_timer: timer for MLB device in case of lost interrupt or buffer not
+ * emptied
+ * @active_channels: bitmap of active channels
+ * @mlb_lock: indicates MLB locked
+ * @net_lock: indicates MOST locked
+ * @chantab: converts internal channel number to MOST channel number.
+ * @channels: data for individual channel
+ * @dentry: debug fs dentry instance
+ */
+struct sta2x11_mlb {
+ void *base;
+ struct pci_dev *pdev;
+ struct most_dev *mdev;
+ spinlock_t lock; /* mutual exclusion */
+ int disabled;
+ int opened;
+ struct timer_list poll_timer;
+ u32 active_channels;
+ enum lock mlb_lock;
+ enum lock net_lock;
+ u8 chantab[(MAX_LCHAN >> 1) + 1];
+ struct sta2x11_mlb_chan channels[MAX_CHANNELS];
+ struct dentry *dentry;
+ struct debugfs_regset32 *regset;
+};
+
+#endif /* STA2X11MLB_H_ */
--
1.7.7.2
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists