diff options
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-langwell-dma-driver-3.0.patch')
-rw-r--r-- | meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-langwell-dma-driver-3.0.patch | 2469 |
1 files changed, 0 insertions, 2469 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-langwell-dma-driver-3.0.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-langwell-dma-driver-3.0.patch deleted file mode 100644 index d539b6092..000000000 --- a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-langwell-dma-driver-3.0.patch +++ /dev/null @@ -1,2469 +0,0 @@ -Index: linux-2.6.33/drivers/dma/Kconfig -=================================================================== ---- linux-2.6.33.orig/drivers/dma/Kconfig -+++ linux-2.6.33/drivers/dma/Kconfig -@@ -20,6 +20,37 @@ comment "DMA Devices" - config ASYNC_TX_DISABLE_CHANNEL_SWITCH - bool - -+config INTEL_LNW_DMAC1 -+ bool "Intel MID DMA support for LPE DMA" -+ depends on PCI && X86 && (SND_INTEL_SST||SND_INTEL_LPE) -+ select DMA_ENGINE -+ help -+ Enable support for the Intel(R) MID DMA1 engine present -+ in Intel MID chipsets. -+ -+ Say Y here if you have such a chipset. -+ -+ If unsure, say N. -+ -+config INTEL_LNW_DMAC2 -+ bool "Intel MID DMA support for SC DMA" -+ depends on PCI && X86 -+ select DMA_ENGINE -+ help -+ Enable support for the Intel(R) MID DMA2 engine present -+ in Intel MID chipsets. -+ -+ Say Y here if you have such a chipset. -+ -+ If unsure, say N. -+ -+config LNW_DMA_DEBUG -+ bool "LNW DMA Debugging Enable" -+ depends on INTEL_LNW_DMAC1 || INTEL_LNW_DMAC2 -+ default N -+ help -+ Enable logging in the LNW DMA drivers -+ - config INTEL_IOATDMA - tristate "Intel I/OAT DMA support" - depends on PCI && X86 -Index: linux-2.6.33/drivers/dma/Makefile -=================================================================== ---- linux-2.6.33.orig/drivers/dma/Makefile -+++ linux-2.6.33/drivers/dma/Makefile -@@ -1,5 +1,7 @@ - obj-$(CONFIG_DMA_ENGINE) += dmaengine.o - obj-$(CONFIG_NET_DMA) += iovlock.o -+obj-$(CONFIG_INTEL_LNW_DMAC2) += lnw_dmac2.o -+obj-$(CONFIG_INTEL_LNW_DMAC1) += lnw_dmac1.o - obj-$(CONFIG_DMATEST) += dmatest.o - obj-$(CONFIG_INTEL_IOATDMA) += ioat/ - obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o -Index: linux-2.6.33/drivers/dma/lnw_dma_regs.h -=================================================================== ---- /dev/null -+++ linux-2.6.33/drivers/dma/lnw_dma_regs.h -@@ -0,0 +1,176 @@ -+/* -+ * lnw_dma.c - Intel Langwell DMA Drivers -+ * -+ * Copyright (C) 2008-09 Intel Corp -+ * Author: Vinod Koul <vinod.koul@intel.com> -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * 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., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * -+ */ -+#ifndef __LNW_DMA_REGS_H__ -+#define __LNW_DMA_REGS_H__ -+ -+#include <linux/dmaengine.h> -+#include <linux/dmapool.h> -+#include <linux/pci_ids.h> -+ -+#define LNW_DMA_DRIVER_VERSION "0.3.1" -+ -+#define DMA_DEBUG -+ -+#define REG_BIT0 0x00000001 -+#define REG_BIT8 0x00000100 -+ -+#define UNMASK_INTR_REG(chan_num) \ -+ ((REG_BIT0 << chan_num) | (REG_BIT8 << chan_num)) -+#define MASK_INTR_REG(chan_num) (REG_BIT8 << chan_num) -+ -+#define ENABLE_CHANNEL(chan_num) \ -+ ((REG_BIT0 << chan_num) | (REG_BIT8 << chan_num)) -+ -+#define DESCS_PER_CHANNEL 16 -+/*DMA Registers*/ -+/*registers associated with channel programming*/ -+#define DMA_REG_SIZE 0x400 -+#define DMA_CH_SIZE 0x58 -+ -+/*CH X REG = (DMA_CH_SIZE)*CH_NO + REG*/ -+#define SAR 0x00 /* Source Address Register*/ -+#define DAR 0x08 /* Destination Address Register*/ -+#define CTL_LOW 0x18 /* Control Register*/ -+#define CTL_HIGH 0x1C /* Control Register*/ -+#define CFG_LOW 0x40 /* Configuration Register Low*/ -+#define CFG_HIGH 0x44 /* Configuration Register high*/ -+ -+#define STATUS_TFR 0x2E8 -+#define STATUS_BLOCK 0x2F0 -+#define STATUS_ERR 0x308 -+ -+#define RAW_TFR 0x2C0 -+#define RAW_BLOCK 0x2C8 -+#define RAW_ERR 0x2E0 -+ -+#define MASK_TFR 0x310 -+#define MASK_BLOCK 0x318 -+#define MASK_SRC_TRAN 0x320 -+#define MASK_DST_TRAN 0x328 -+#define MASK_ERR 0x330 -+ -+#define CLEAR_TFR 0x338 -+#define CLEAR_BLOCK 0x340 -+#define CLEAR_SRC_TRAN 0x348 -+#define CLEAR_DST_TRAN 0x350 -+#define CLEAR_ERR 0x358 -+ -+#define INTR_STATUS 0x360 -+#define DMA_CFG 0x398 -+#define DMA_CHAN_EN 0x3A0 -+ -+/** -+ * struct lnw_dma_chan - internal representation of a DMA channel -+ */ -+struct lnw_dma_chan { -+ struct dma_chan chan; -+ void __iomem *ch_regs; -+ void __iomem *dma_base; -+ int ch_id; -+ spinlock_t lock; -+ dma_cookie_t completed; -+ struct list_head active_list; -+ struct list_head queue; -+ struct list_head free_list; -+ struct lnw_dma_slave *slave; -+ unsigned int descs_allocated; -+ struct lnwdma_device *dma; -+ bool in_use; -+}; -+static inline struct lnw_dma_chan *to_lnw_dma_chan(struct dma_chan *chan) -+{ -+ return container_of(chan, struct lnw_dma_chan, chan); -+} -+ -+/** -+ * struct lnwdma_device - internal representation of a DMA device -+ * @pdev: PCI device -+ * @dma_base: MMIO register space base address of DMA -+ * @lpe_base: MMIO register space base address of LPE -+ * @dma_pool: for allocating DMA descriptors -+ * @common: embedded struct dma_device -+ * @idx: per channel data -+ */ -+struct lnwdma_device { -+ struct pci_dev *pdev; -+ void __iomem *dma_base; -+ struct pci_pool *dma_pool; -+ struct dma_device common; -+ struct tasklet_struct tasklet; -+ struct lnw_dma_chan ch[MAX_CHAN]; -+}; -+ -+static inline struct lnwdma_device *to_lnwdma_device(struct dma_device *common) -+{ -+ return container_of(common, struct lnwdma_device, common); -+} -+ -+struct lnw_dma_desc { -+ void __iomem *block; /*ch ptr*/ -+ struct list_head desc_node; -+ struct dma_async_tx_descriptor txd; -+ size_t len; -+ dma_addr_t sar; -+ dma_addr_t dar; -+ u32 cfg_hi; -+ u32 cfg_lo; -+ u32 ctl_lo; -+ u32 ctl_hi; -+ dma_addr_t next; -+ enum dma_data_direction dirn; -+ enum dma_status status; -+ dma_async_tx_callback callback; -+ void *callback_param; -+ enum lnw_dma_width width; /*width of DMA txn*/ -+ enum lnw_dma_mode cfg_mode; /*mode configuration*/ -+ -+}; -+ -+static inline int test_ch_en(void __iomem *dma, u32 ch_no) -+{ -+ u32 en_reg = ioread32(dma + DMA_CHAN_EN); -+ return (en_reg >> ch_no) & 0x1; -+} -+ -+static inline struct lnw_dma_desc *to_lnw_dma_desc -+ (struct dma_async_tx_descriptor *txd) -+{ -+ return container_of(txd, struct lnw_dma_desc, txd); -+} -+ -+#define _dma_printk(level, format, arg...) \ -+ printk(level "LNW_DMA: %s %d " format, __func__, __LINE__, ## arg) -+ -+#ifdef CONFIG_LNW_DMA_DEBUG -+#define dma_dbg(format, arg...) _dma_printk(KERN_DEBUG, "DBG " format , ## arg) -+#else -+#define dma_dbg(format, arg...) do {} while (0); -+#endif -+ -+#define dma_err(format, arg...) _dma_printk(KERN_ERR, "ERR " format , ## arg) -+#define dma_info(format, arg...) \ -+ _dma_printk(KERN_INFO , "INFO " format , ## arg) -+ -+#endif /*__LNW_DMA_REGS_H__*/ -Index: linux-2.6.33/drivers/dma/lnw_dmac1.c -=================================================================== ---- /dev/null -+++ linux-2.6.33/drivers/dma/lnw_dmac1.c -@@ -0,0 +1,957 @@ -+/* -+ * lnw_dmac1.c - Intel Langwell DMA Drivers -+ * -+ * Copyright (C) 2008-09 Intel Corp -+ * Authhor: Vinod Koul <vinod.koul@intel.com> -+ * The driver design is based on dw_dmac driver -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * 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., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * -+ */ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/interrupt.h> -+#include <sound/intel_lpe.h> -+#include <linux/lnw_dma.h> -+ -+#define MAX_CHAN 2 -+#include "lnw_dma_regs.h" -+ -+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); -+MODULE_DESCRIPTION("Intel (R) Moorestown Langwell DMAC1 Driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_VERSION(LNW_DMA_DRIVER_VERSION); -+ -+#define DMA_CH0 6 -+#define DMA_CH1 7 -+#define CH_BLOCK_SIZE 4095 -+ -+static int __devinit lnw_dma1_probe(struct pci_dev *pdev, -+ const struct pci_device_id *id); -+static void __devexit lnw_dma1_remove(struct pci_dev *pdev); -+static void enable_dma1_interrupt(struct lnw_dma_chan *lnwc); -+static void disable_dma1_interrupt(struct lnw_dma_chan *lnwc); -+ -+struct lnw_device { -+ struct pci_dev *pdev; -+ void __iomem *dma_base; -+ struct lnwdma_device *dma; -+}; -+ -+/*CH dep code, if ch no's mapping changes only change here*/ -+static int get_ch_id(int index) -+{ -+ if (index == 0) -+ return DMA_CH0; -+ else if (index == 1) -+ return DMA_CH1; -+ else -+ return -1; -+} -+ -+static int get_ch_index(int ch_id) -+{ -+ if (ch_id == DMA_CH0) -+ return 0; -+ if (ch_id == DMA_CH1) -+ return 1; -+ else -+ return -1; -+} -+ -+static int get_ch_num(int *status) -+{ -+ if (*status & (1 << DMA_CH0)) { -+ *status = *status & (~(1 << DMA_CH0)); -+ return DMA_CH0; -+ } else if (*status & (1 << DMA_CH1)) { -+ *status = *status & (~(1 << DMA_CH1)); -+ return DMA_CH1; -+ } else -+ return -1; -+} -+ -+static int get_block_ts(int len, int tx_width) -+{ -+ int byte_width = 0, block_ts = 0; -+ -+ switch (tx_width) { -+ case LNW_DMA_WIDTH_8BIT: -+ byte_width = 1; -+ break; -+ case LNW_DMA_WIDTH_16BIT: -+ byte_width = 2; -+ break; -+ case LNW_DMA_WIDTH_32BIT: -+ default: -+ byte_width = 4; -+ break; -+ } -+ -+ block_ts = len/byte_width; -+ if (block_ts > CH_BLOCK_SIZE) -+ block_ts = 0xFFFF; -+ return block_ts; -+} -+ -+static struct lnw_dma_desc *lnwc_desc_get1(struct lnw_dma_chan *lnwc) -+{ -+ struct lnw_dma_desc *desc, *_desc; -+ struct lnw_dma_desc *ret = NULL; -+ -+ dma_dbg("called \n"); -+ spin_lock_bh(&lnwc->lock); -+ list_for_each_entry_safe(desc, _desc, &lnwc->free_list, desc_node) { -+ if (async_tx_test_ack(&desc->txd)) { -+ list_del(&desc->desc_node); -+ ret = desc; -+ dma_dbg("got free desc \n"); -+ break; -+ } -+ } -+ spin_unlock_bh(&lnwc->lock); -+ return ret; -+} -+ -+ -+static void lnwc_desc_put1(struct lnw_dma_chan *lnwc, struct lnw_dma_desc *desc) -+{ -+ if (desc) { -+ spin_lock_bh(&lnwc->lock); -+ list_add_tail(&desc->desc_node, &lnwc->free_list); -+ spin_unlock_bh(&lnwc->lock); -+ } -+} -+ -+/* Called with dwc->lock held and bh disabled */ -+static void lnwc_dostart1(struct lnw_dma_chan *lnwc, struct lnw_dma_desc *first) -+{ -+ struct lnwdma_device *lnw = to_lnwdma_device(lnwc->chan.device); -+ -+ dma_dbg("called \n"); -+ /* ASSERT: channel is idle */ -+ if (lnwc->in_use && test_ch_en(lnwc->dma_base, lnwc->ch_id)) { -+ /*error*/ -+ dma_err("channel is busy \n"); -+ /* The tasklet will hopefully advance the queue... */ -+ return; -+ } -+ -+ /*write registers and en*/ -+ iowrite32(first->sar, lnwc->ch_regs + SAR); -+ iowrite32(first->dar, lnwc->ch_regs + DAR); -+ iowrite32(first->cfg_hi, lnwc->ch_regs + CFG_HIGH); -+ iowrite32(first->cfg_lo, lnwc->ch_regs + CFG_LOW); -+ iowrite32(first->ctl_lo, lnwc->ch_regs + CTL_LOW); -+ iowrite32(first->ctl_hi, lnwc->ch_regs + CTL_HIGH); -+ dma_dbg("TX SAR %lx, DAR %lx, CFGL %x, CFGH %x, CTLH %x, CTLL %x \n", -+ first->sar, first->dar, first->cfg_hi, -+ first->cfg_lo, first->ctl_hi, first->ctl_lo); -+ -+ iowrite32(ENABLE_CHANNEL(lnwc->ch_id), lnw->dma_base + DMA_CHAN_EN); -+ first->status = DMA_IN_PROGRESS; -+} -+ -+static void -+lnwc_descriptor_complete1(struct lnw_dma_chan *lnwc, struct lnw_dma_desc *desc) -+{ -+ struct dma_async_tx_descriptor *txd = &desc->txd; -+ dma_async_tx_callback callback = NULL; -+ dma_async_tx_callback callback_txd = NULL; -+ void *param = NULL; -+ void *param_txd = NULL; -+ u32 sar, dar, len; -+ union lnw_dma_ctl_hi ctl_hi; -+ -+ dma_dbg("called \n"); -+ -+ /*check if full tx is complete or not*/ -+ sar = ioread32(lnwc->ch_regs + SAR); -+ dar = ioread32(lnwc->ch_regs + DAR); -+ -+ if (desc->dirn == DMA_FROM_DEVICE) -+ len = dar - desc->dar; -+ else -+ len = sar - desc->sar; -+ -+ dma_dbg("SAR %x DAR %x, DMA done: %x \n", sar, dar, len); -+ if (desc->len > len) { -+ dma_dbg("dirn = %d\n", desc->dirn); -+ dma_dbg("SAR %x DAR %x, len: %x \n", sar, dar, len); -+ /*we have to copy more bytes*/ -+ desc->len -= len; -+ ctl_hi.ctl_hi = desc->ctl_hi; -+ ctl_hi.ctlx.block_ts = get_block_ts(desc->len, desc->width); -+ dma_dbg("setting for %x bytes \n", ctl_hi.ctlx.block_ts); -+ desc->ctl_hi = ctl_hi.ctl_hi; -+ if (desc->cfg_mode == LNW_DMA_MEM_TO_MEM) { -+ sar++; -+ dar++; -+ } else if (desc->dirn == DMA_TO_DEVICE) -+ sar++; -+ else if (desc->dirn == DMA_FROM_DEVICE) -+ dar++; -+ desc->sar = sar; -+ desc->dar = dar; -+ dma_dbg("New SAR %x DAR %x \n", sar, dar); -+ lnwc_dostart1(lnwc, desc); -+ return; -+ } -+ -+ lnwc->completed = txd->cookie; -+ callback = desc->callback; -+ param = desc->callback_param; -+ callback_txd = txd->callback; -+ param_txd = txd->callback_param; -+ -+ list_move(&desc->desc_node, &lnwc->free_list); -+ -+ spin_unlock_bh(&lnwc->lock); -+ dma_dbg("Now we are calling callback \n"); -+ if (callback_txd) { -+ dma_dbg("lnw TXD callback set ... calling \n"); -+ callback_txd(param_txd); -+ spin_lock_bh(&lnwc->lock); -+ return; -+ } -+ if (callback) { -+ dma_dbg("lnw callback set ... calling \n"); -+ callback(param); -+ } -+ spin_lock_bh(&lnwc->lock); -+} -+ -+/*check desc, mark as complete when tx is complete*/ -+static void -+lnwc_scan_descriptors1(struct lnwdma_device *lnw, struct lnw_dma_chan *lnwc) -+{ -+ struct lnw_dma_desc *desc = NULL, *_desc = NULL; -+ u32 status_xfer; -+ -+ dma_dbg("called \n"); -+ status_xfer = ioread32(lnwc->dma_base + RAW_BLOCK); -+ status_xfer = (status_xfer >> lnwc->ch_id) & 0x1; -+ dma_dbg("ch[%d]: status_xfer %x \n", lnwc->ch_id, status_xfer); -+ if (!status_xfer) -+ return; -+ -+ list_for_each_entry_safe(desc, _desc, &lnwc->active_list, desc_node) { -+ if (desc == NULL) -+ continue; -+ if (desc->status == DMA_IN_PROGRESS) { -+ desc->status = DMA_SUCCESS; -+ lnwc_descriptor_complete1(lnwc, desc); -+ } -+ } -+ return; -+} -+ -+/***************************************************************************** -+DMA Functions*/ -+static dma_cookie_t lnw_dma1_tx_submit(struct dma_async_tx_descriptor *tx) -+{ -+ struct lnw_dma_desc *desc = to_lnw_dma_desc(tx); -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(tx->chan); -+ dma_cookie_t cookie; -+ -+ dma_dbg("called \n"); -+ spin_lock_bh(&lnwc->lock); -+ cookie = lnwc->chan.cookie; -+ -+ if (++cookie < 0) -+ cookie = 1; -+ -+ lnwc->chan.cookie = cookie; -+ desc->txd.cookie = cookie; -+ -+ -+ if (list_empty(&lnwc->active_list)) { -+ lnwc_dostart1(lnwc, desc); -+ list_add_tail(&desc->desc_node, &lnwc->active_list); -+ } else { -+ list_add_tail(&desc->desc_node, &lnwc->queue); -+ } -+ spin_unlock_bh(&lnwc->lock); -+ -+ return cookie; -+} -+ -+static void lnw_dma1_issue_pending(struct dma_chan *chan) -+{ -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(chan); -+ -+ spin_lock_bh(&lnwc->lock); -+ if (!list_empty(&lnwc->queue)) -+ lnwc_scan_descriptors1(to_lnwdma_device(chan->device), lnwc); -+ spin_unlock_bh(&lnwc->lock); -+} -+ -+static enum dma_status -+lnw_dma1_tx_is_complete(struct dma_chan *chan, -+ dma_cookie_t cookie, -+ dma_cookie_t *done, -+ dma_cookie_t *used) -+{ -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(chan); -+ dma_cookie_t last_used; -+ dma_cookie_t last_complete; -+ int ret; -+ -+ last_complete = lnwc->completed; -+ last_used = chan->cookie; -+ -+ ret = dma_async_is_complete(cookie, last_complete, last_used); -+ if (ret != DMA_SUCCESS) { -+ lnwc_scan_descriptors1(to_lnwdma_device(chan->device), lnwc); -+ -+ last_complete = lnwc->completed; -+ last_used = chan->cookie; -+ -+ ret = dma_async_is_complete(cookie, last_complete, last_used); -+ } -+ -+ if (done) -+ *done = last_complete; -+ if (used) -+ *used = last_used; -+ -+ return ret; -+} -+ -+static void lnw_dma1_terminate_all(struct dma_chan *chan) -+{ -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(chan); -+ struct lnwdma_device *lnw = to_lnwdma_device(chan->device); -+ struct lnw_dma_desc *desc, *_desc; -+ LIST_HEAD(list); -+ -+ /* ASSERT: channel is idle */ -+ if (lnwc->in_use == false) { -+ /*ch is not in use, wrong call*/ -+ return; -+ } -+ spin_lock_bh(&lnwc->lock); -+ list_splice_init(&lnwc->free_list, &list); -+ lnwc->descs_allocated = 0; -+ lnwc->slave = NULL; -+ -+ /* Disable interrupts */ -+ disable_dma1_interrupt(lnwc); -+ -+ spin_unlock_bh(&lnwc->lock); -+ list_for_each_entry_safe(desc, _desc, &list, desc_node) { -+ dma_dbg("freeing descriptor %p\n", desc); -+ pci_pool_free(lnw->dma_pool, desc, desc->txd.phys); -+ } -+ return; -+} -+ -+static struct dma_async_tx_descriptor * -+lnw_dma1_prep_slave_sg(struct dma_chan *chan, -+ struct scatterlist *sgl, unsigned int sg_len, -+ enum dma_data_direction direction, -+ unsigned long flags) -+{ -+ /*not supported now*/ -+ return NULL; -+} -+ -+static struct dma_async_tx_descriptor * -+lnw_dma1_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, -+ dma_addr_t src, size_t len, unsigned long flags) -+{ -+ struct lnw_dma_chan *lnwc; -+ struct lnw_dma_desc *desc = NULL; -+ struct lnw_dma_slave *lnws; -+ union lnw_dma_ctl_lo ctl_lo; -+ union lnw_dma_ctl_hi ctl_hi; -+ union lnw_dma_cfg_lo cfg_lo; -+ union lnw_dma_cfg_hi cfg_hi; -+ enum lnw_dma_width width = 0; -+ -+ dma_dbg("called \n"); -+ WARN_ON(!chan); -+ if (!len) -+ return NULL; -+ -+ lnws = chan->private; -+ WARN_ON(!lnws); -+ -+ lnwc = to_lnw_dma_chan(chan); -+ WARN_ON(!lnwc); -+ -+ dma_dbg("called for CH %d\n", lnwc->ch_id); -+ dma_dbg("Cfg passed Mode %x, Dirn %x, HS %x, Width %x \n", -+ lnws->cfg_mode, lnws->dirn, lnws->hs_mode, lnws->src_width); -+ -+ /*calculate CFG_LO*/ -+ if (lnws->hs_mode == LNW_DMA_SW_HS) { -+ cfg_lo.cfg_lo = 0; -+ cfg_lo.cfgx.hs_sel_dst = 1; -+ cfg_lo.cfgx.hs_sel_src = 1; -+ } else if (lnws->hs_mode == LNW_DMA_HW_HS) -+ cfg_lo.cfg_lo = 0x00000; -+ -+ /*calculate CFG_HI*/ -+ if (lnws->cfg_mode == LNW_DMA_MEM_TO_MEM) { -+ /*SW HS only*/ -+ dma_dbg("CFG: Mem to mem dma \n"); -+ cfg_hi.cfg_hi = 0; -+ } else { -+ dma_dbg("HW DMA \n"); -+ cfg_hi.cfg_hi = 0; -+ cfg_hi.cfgx.protctl = 0x0; /*default value*/ -+ cfg_hi.cfgx.fifo_mode = 1; -+ if (lnws->dirn == DMA_TO_DEVICE) { -+ cfg_hi.cfgx.src_per = 0; -+ cfg_hi.cfgx.dst_per = 3; -+ } else if (lnws->dirn == DMA_FROM_DEVICE) { -+ cfg_hi.cfgx.src_per = 2; -+ cfg_hi.cfgx.dst_per = 0; -+ } -+ } -+ -+ /*calculate CTL_HI*/ -+ ctl_hi.ctlx.reser = 0; -+ width = lnws->src_width; -+ -+ ctl_hi.ctlx.block_ts = get_block_ts(len, width); -+ -+ /*calculate CTL_LO*/ -+ ctl_lo.ctl_lo = 0; -+ ctl_lo.ctlx.int_en = 1; -+ ctl_lo.ctlx.dst_tr_width = lnws->dst_width; -+ ctl_lo.ctlx.src_tr_width = lnws->src_width; -+ ctl_lo.ctlx.dst_msize = lnws->src_msize; -+ ctl_lo.ctlx.src_msize = lnws->dst_msize; -+ -+ if (lnws->cfg_mode == LNW_DMA_MEM_TO_MEM) { -+ dma_dbg("CTL: Mem to mem dma \n"); -+ ctl_lo.ctlx.tt_fc = 0; -+ ctl_lo.ctlx.sinc = 0; -+ ctl_lo.ctlx.dinc = 0; -+ } else { -+ if (lnws->dirn == DMA_TO_DEVICE) { -+ dma_dbg("CTL: DMA_TO_DEVICE \n"); -+ ctl_lo.ctlx.sinc = 0; -+ ctl_lo.ctlx.dinc = 2; -+ ctl_lo.ctlx.tt_fc = 1; -+ } else if (lnws->dirn == DMA_FROM_DEVICE) { -+ dma_dbg("CTL: DMA_FROM_DEVICE \n"); -+ ctl_lo.ctlx.sinc = 2; -+ ctl_lo.ctlx.dinc = 0; -+ ctl_lo.ctlx.tt_fc = 2; -+ } -+ } -+ -+ dma_dbg("Calc CTL LO %x, CTL HI %x, CFG LO %x, CFG HI %x\n", -+ ctl_lo.ctl_lo, ctl_hi.ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi); -+ -+ enable_dma1_interrupt(lnwc); -+ -+ desc = lnwc_desc_get1(lnwc); -+ if (desc == NULL) -+ goto err_desc_get; -+ desc->sar = src; -+ desc->dar = dest ; -+ desc->len = len; -+ desc->cfg_hi = cfg_hi.cfg_hi; -+ desc->cfg_lo = cfg_lo.cfg_lo; -+ desc->ctl_lo = ctl_lo.ctl_lo; -+ desc->ctl_hi = ctl_hi.ctl_hi; -+ desc->width = width; -+ desc->dirn = lnws->dirn; -+ if (lnws->callback) { -+ desc->callback = lnws->callback; -+ desc->callback_param = lnws->callback_param; -+ dma_dbg("Callback passed... setting\n"); -+ } else -+ desc->callback = NULL; -+ return &desc->txd; -+ -+err_desc_get: -+ dma_err("Failed to get desc \n"); -+ lnwc_desc_put1(lnwc, desc); -+ return NULL; -+} -+ -+static void lnw_dma1_free_chan_resources(struct dma_chan *chan) -+{ -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(chan); -+ struct lnwdma_device *lnw = to_lnwdma_device(chan->device); -+ struct lnw_dma_desc *desc, *_desc; -+ -+ dma_dbg("..called for ch_id %d, lnwch_id %d\n", -+ chan->chan_id, lnwc->ch_id); -+ if (true == lnwc->in_use) { -+ /*trying to free ch in use!!!!!*/ -+ dma_err("trying to free ch in use \n"); -+ } -+ -+ spin_lock_bh(&lnwc->lock); -+ lnwc->descs_allocated = 0; -+ list_for_each_entry_safe(desc, _desc, &lnwc->active_list, desc_node) { -+ dma_dbg("del active \n"); -+ list_del(&desc->desc_node); -+ pci_pool_free(lnw->dma_pool, desc, desc->txd.phys); -+ } -+ list_for_each_entry_safe(desc, _desc, &lnwc->free_list, desc_node) { -+ list_del(&desc->desc_node); -+ pci_pool_free(lnw->dma_pool, desc, desc->txd.phys); -+ } -+ list_for_each_entry_safe(desc, _desc, &lnwc->queue, desc_node) { -+ dma_dbg("del queue \n"); -+ list_del(&desc->desc_node); -+ pci_pool_free(lnw->dma_pool, desc, desc->txd.phys); -+ } -+ spin_unlock_bh(&lnwc->lock); -+ lnwc->in_use = false; -+ chan->client_count--; -+ /* Disable CH interrupts */ -+ iowrite32(MASK_INTR_REG(lnwc->ch_id), lnw->dma_base + MASK_BLOCK); -+ iowrite32(MASK_INTR_REG(lnwc->ch_id), lnw->dma_base + MASK_ERR); -+ dma_dbg("done \n"); -+} -+ -+static int lnw_dma1_alloc_chan_resources(struct dma_chan *chan) -+{ -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(chan); -+ struct lnwdma_device *lnw = to_lnwdma_device(chan->device); -+ struct lnw_dma_desc *desc; -+ dma_addr_t phys; -+ int i = 0; -+ -+ dma_dbg("called \n"); -+ -+ /* ASSERT: channel is idle */ -+ if (test_ch_en(lnw->dma_base, lnwc->ch_id)) { -+ /*ch is not idle*/ -+ dma_err(".ch not idle\n"); -+ return -EIO; -+ } -+ dma_dbg("..called for ch_id %d, lnwch_id %d\n", -+ chan->chan_id, lnwc->ch_id); -+ lnwc->completed = chan->cookie = 1; -+ -+ chan->client_count++; -+ -+ spin_lock_bh(&lnwc->lock); -+ while (lnwc->descs_allocated < DESCS_PER_CHANNEL) { -+ spin_unlock_bh(&lnwc->lock); -+ desc = pci_pool_alloc(lnw->dma_pool, GFP_KERNEL, &phys); -+ if (!desc) { -+ dma_err("desc failed\n"); -+ return -ENOMEM; -+ /*check*/ -+ } -+ dma_async_tx_descriptor_init(&desc->txd, chan); -+ desc->txd.tx_submit = lnw_dma1_tx_submit; -+ desc->txd.flags = DMA_CTRL_ACK; -+ desc->txd.phys = phys; -+ spin_lock_bh(&lnwc->lock); -+ i = ++lnwc->descs_allocated; -+ list_add_tail(&desc->desc_node, &lnwc->free_list); -+ } -+ spin_unlock_bh(&lnwc->lock); -+ lnwc->in_use = false; -+ dma_dbg("Desc alloc done ret: %d desc\n", i); -+ return i; -+} -+ -+static void lnwc_handle_error1(struct lnwdma_device *lnw, -+ struct lnw_dma_chan *lnwc) -+{ -+ lnwc_scan_descriptors1(lnw, lnwc); -+} -+ -+/****************************************************************************** -+* PCI stuff -+*/ -+static struct pci_device_id lnw_dma1_ids[] = { -+ { PCI_VENDOR_ID_INTEL, 0x0814, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { 0, } -+}; -+ -+MODULE_DEVICE_TABLE(pci, lnw_dma1_ids); -+ -+static struct pci_driver lnw_dma1_pci = { -+ .name = "Intel LNW DMA1", -+ .id_table = lnw_dma1_ids, -+ .probe = lnw_dma1_probe, -+ .remove = __devexit_p(lnw_dma1_remove), -+}; -+ -+static void dma_tasklet1(unsigned long data) -+{ -+ struct lnwdma_device *lnw = NULL; -+ struct lnw_dma_chan *lnwc = NULL; -+ u32 status; -+ int i, ch_no; -+ -+ dma_dbg("called \n"); -+ lnw = (struct lnwdma_device *)data; -+ if (lnw == NULL) { -+ dma_err("Null param \n"); -+ return; -+ } -+ status = ioread32(lnw->dma_base + RAW_BLOCK); -+ dma_dbg("RAW_TFR %x \n", status); -+ status &= 0xC0; -+ while (status) { -+ /*txn interrupt*/ -+ ch_no = get_ch_num(&status); -+ if (ch_no < 0) { -+ dma_err("Ch no is invalid %x, abort!\n", ch_no); -+ return; -+ } -+ dma_dbg("Got Ch %x, new Status %x \n", ch_no, status); -+ i = get_ch_index(ch_no); -+ if (i < 0) { -+ dma_err("Invalid ch index %x\n", i); -+ return; -+ } -+ dma_dbg("Tx complete interrupt %x, Ch No %d Index %d \n", -+ status, ch_no, i); -+ lnwc = &lnw->ch[i]; -+ if (lnwc == NULL) { -+ dma_err("Null param lnwc\n"); -+ return; -+ } -+ dma_dbg("CH %x \n", lnwc->ch_id); -+ spin_lock_bh(&lnwc->lock); -+ lnwc_scan_descriptors1(lnw, lnwc); -+ dma_dbg("Scan of desc... complete, unmasking\n"); -+ iowrite32((1 << lnwc->ch_id), -+ lnw->dma_base + CLEAR_TFR); -+ dma_dbg("Wrote to clear %x\n", (1 << lnwc->ch_id)); -+ iowrite32((1 << lnwc->ch_id), -+ lnw->dma_base + CLEAR_BLOCK); -+ iowrite32(UNMASK_INTR_REG(lnwc->ch_id), -+ lnw->dma_base + MASK_TFR); -+ spin_unlock_bh(&lnwc->lock); -+ } -+ -+ dma_dbg("Trf interrupt done... \n"); -+ status = ioread32(lnw->dma_base + RAW_ERR); -+ status &= 0xC0; -+ while (status) { -+ /*err interrupt*/ -+ ch_no = get_ch_num(&status); -+ if (ch_no < 0) { -+ dma_err("Ch no is invalid %x, abort!\n", ch_no); -+ return; -+ } -+ dma_dbg("Got Ch %x, new Status %x \n", ch_no, status); -+ i = get_ch_index(ch_no); -+ if (i < 0) { -+ dma_err("Invalid CH lnwc\n"); -+ return; -+ } -+ dma_dbg("Tx error interrupt %x, No %d Index %d \n", -+ status, ch_no, i); -+ lnwc = &lnw->ch[i]; -+ if (lnwc == NULL) { -+ dma_err("Null param lnwc\n"); -+ return; -+ } -+ spin_lock_bh(&lnwc->lock); -+ lnwc_handle_error1(lnw, lnwc); -+ iowrite32((1 << lnwc->ch_id), -+ lnw->dma_base + CLEAR_ERR); -+ iowrite32(UNMASK_INTR_REG(lnwc->ch_id), -+ lnw->dma_base + MASK_ERR); -+ spin_unlock_bh(&lnwc->lock); -+ } -+ dma_dbg("Exiting takslet... \n"); -+ return; -+} -+ -+static irqreturn_t lnw_dma1_interrupt(int irq, void *data) -+{ -+ struct lnw_device *lnw = data; -+ u32 status; -+ int call_tasklet = 0; -+ -+ /*check interrupt src*/ -+ lpe_periphral_intr_status(LPE_DMA, &status); -+ if (!status) { -+ /*not our interrupt*/ -+ return IRQ_NONE; -+ } -+ -+ /*DMA Interrupt*/ -+ status = ioread32(lnw->dma_base + RAW_TFR); -+ status &= 0xC0; -+ if (status) { -+ iowrite32((status << 8), lnw->dma_base + MASK_TFR); -+ call_tasklet = 1; -+ } -+ status = ioread32(lnw->dma_base + RAW_ERR); -+ status &= 0xC0; -+ if (status) { -+ iowrite32(MASK_INTR_REG(status), lnw->dma_base + MASK_ERR); -+ call_tasklet = 1; -+ } -+ -+ if (call_tasklet) -+ tasklet_schedule(&lnw->dma->tasklet); -+ -+ return IRQ_HANDLED; -+} -+ -+static void enable_dma1_interrupt(struct lnw_dma_chan *lnwc) -+{ -+ dma_dbg("Called for ch_id %d\n", lnwc->ch_id); -+ -+ lpe_unmask_periphral_intr(LPE_DMA); -+ -+ /*en ch interrupts*/ -+ iowrite32(UNMASK_INTR_REG(lnwc->ch_id), lnwc->dma_base + MASK_TFR); -+ iowrite32(UNMASK_INTR_REG(lnwc->ch_id), lnwc->dma_base + MASK_ERR); -+ return; -+} -+ -+static void disable_dma1_interrupt(struct lnw_dma_chan *lnwc) -+{ -+ /*Check LPE PISR, make sure fwd is disabled*/ -+ lpe_mask_periphral_intr(LPE_DMA); -+ iowrite32(MASK_INTR_REG(lnwc->ch_id), lnwc->dma_base + MASK_BLOCK); -+ iowrite32(MASK_INTR_REG(lnwc->ch_id), lnwc->dma_base + MASK_TFR); -+ iowrite32(MASK_INTR_REG(lnwc->ch_id), lnwc->dma_base + MASK_ERR); -+ dma_dbg(" called \n"); -+ return; -+} -+ -+static int lnw_setup_dma1(struct pci_dev *pdev) -+{ -+ struct lnw_device *device = pci_get_drvdata(pdev); -+ struct lnwdma_device *dma = NULL; -+ int err, i; -+ -+ dma_dbg("setup_dma called \n"); -+ dma = kzalloc(sizeof(*dma), GFP_KERNEL); -+ if (NULL == dma) { -+ dma_err("kzalloc failed \n"); -+ err = -ENOMEM; -+ goto err_kzalloc; -+ } -+ device->dma = dma; -+ dma->pdev = pdev; -+ dma->dma_base = device->dma_base; -+ -+ /* DMA coherent memory pool for DMA descriptor allocations */ -+ dma->dma_pool = pci_pool_create("dma_desc_pool", pdev, -+ sizeof(struct lnw_dma_desc), -+ 32, 0); -+ if (NULL == dma->dma_pool) { -+ dma_err("pci_pool_create failed \n"); -+ err = -ENOMEM; -+ kfree(dma); -+ goto err_dma_pool; -+ } -+ -+ INIT_LIST_HEAD(&dma->common.channels); -+ -+ -+ /*init CH structures*/ -+ for (i = 0; i < MAX_CHAN; i++) { -+ struct lnw_dma_chan *lnwch = &dma->ch[i]; -+ -+ lnwch->chan.device = &dma->common; -+ lnwch->chan.cookie = 1; -+ lnwch->chan.chan_id = i; -+ lnwch->ch_id = get_ch_id(i); -+ dma_dbg("Init CH %d, ID %d \n", i, lnwch->ch_id); -+ -+ lnwch->dma_base = dma->dma_base; -+ lnwch->ch_regs = dma->dma_base + DMA_CH_SIZE * lnwch->ch_id; -+ lnwch->dma = dma; -+ spin_lock_init(&lnwch->lock); -+ -+ INIT_LIST_HEAD(&lnwch->active_list); -+ INIT_LIST_HEAD(&lnwch->queue); -+ INIT_LIST_HEAD(&lnwch->free_list); -+ /*mask interrupts*/ -+ iowrite32(MASK_INTR_REG(lnwch->ch_id), -+ dma->dma_base + MASK_BLOCK); -+ iowrite32(MASK_INTR_REG(lnwch->ch_id), -+ dma->dma_base + MASK_SRC_TRAN); -+ iowrite32(MASK_INTR_REG(lnwch->ch_id), -+ dma->dma_base + MASK_DST_TRAN); -+ iowrite32(MASK_INTR_REG(lnwch->ch_id), -+ dma->dma_base + MASK_ERR); -+ iowrite32(MASK_INTR_REG(lnwch->ch_id), -+ dma->dma_base + MASK_TFR); -+ -+ disable_dma1_interrupt(lnwch); -+ list_add_tail(&lnwch->chan.device_node, &dma->common.channels); -+ } -+ -+ /*init dma structure*/ -+ dma_cap_zero(dma->common.cap_mask); -+ dma_cap_set(DMA_MEMCPY, dma->common.cap_mask); -+ dma_cap_set(DMA_SLAVE, dma->common.cap_mask); -+ dma_cap_set(DMA_PRIVATE, dma->common.cap_mask); -+ dma->common.dev = &pdev->dev; -+ dma->common.chancnt = MAX_CHAN; -+ -+ dma->common.device_alloc_chan_resources = -+ lnw_dma1_alloc_chan_resources; -+ dma->common.device_free_chan_resources = -+ lnw_dma1_free_chan_resources; -+ -+ dma->common.device_is_tx_complete = lnw_dma1_tx_is_complete; -+ dma->common.device_prep_dma_memcpy = lnw_dma1_prep_memcpy; -+ dma->common.device_issue_pending = lnw_dma1_issue_pending; -+ dma->common.device_prep_slave_sg = lnw_dma1_prep_slave_sg; -+ dma->common.device_terminate_all = lnw_dma1_terminate_all; -+ -+ /*enable dma cntrl*/ -+ iowrite32(REG_BIT0, dma->dma_base + DMA_CFG); -+ -+ /*register irq*/ -+ err = request_irq(pdev->irq, lnw_dma1_interrupt, -+ IRQF_SHARED, lnw_dma1_pci.name, device); -+ if (0 != err) -+ goto err_irq; -+ -+ /*register device w/ engine*/ -+ err = dma_async_device_register(&dma->common); -+ if (0 != err) { -+ dma_err("device_register failed: %d \n", err); -+ goto err_engine; -+ } -+ tasklet_init(&dma->tasklet, dma_tasklet1, (unsigned long)dma); -+ dma_dbg("...done \n"); -+ return 0; -+ -+err_engine: -+ free_irq(pdev->irq, device); -+err_irq: -+ pci_pool_destroy(dma->dma_pool); -+ kfree(dma); -+err_dma_pool: -+err_kzalloc: -+ dma_err("setup_dma failed: %d \n", err); -+ return err; -+ -+} -+ -+static void lnwdma_shutdown1(struct pci_dev *pdev) -+{ -+ struct lnw_device *device = pci_get_drvdata(pdev); -+ -+ dma_dbg("shutdown called \n"); -+ dma_async_device_unregister(&device->dma->common); -+ pci_pool_destroy(device->dma->dma_pool); -+ if (device->dma_base) -+ iounmap(device->dma_base); -+ free_irq(pdev->irq, device); -+ return; -+} -+ -+static int __devinit -+lnw_dma1_probe(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ struct lnw_device *device = NULL; -+ u32 base_addr = 0, bar_size = 0; -+ int err = 0; -+ -+ dma_info("probe called for %x \n", pdev->device); -+ err = pci_enable_device(pdev); -+ if (err) -+ goto err_enable_device; -+ -+ err = pci_request_regions(pdev, lnw_dma1_pci.name); -+ if (err) -+ goto err_request_regions; -+ -+ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); -+ if (err) -+ goto err_set_dma_mask; -+ -+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); -+ if (err) -+ goto err_set_dma_mask; -+ -+ device = kzalloc(sizeof(*device), GFP_KERNEL); -+ if (!device) { -+ dma_err("kzalloc failed \n"); -+ err = -ENOMEM; -+ goto err_kzalloc; -+ } -+ device->pdev = pci_dev_get(pdev); -+ -+ base_addr = pci_resource_start(pdev, 0); -+ bar_size = pci_resource_len(pdev, 0); -+ dma_dbg("BAR0 %x Size %x \n", base_addr, bar_size); -+ device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE); -+ if (!device->dma_base) { -+ dma_err("ioremap failed \n"); -+ err = -ENOMEM; -+ goto err_ioremap1; -+ } -+ pci_set_drvdata(pdev, device); -+ pci_set_master(pdev); -+ -+ err = lnw_setup_dma1(pdev); -+ if (err) -+ goto err_dma; -+ -+ return 0; -+ -+err_dma: -+ iounmap(device->dma_base); -+err_ioremap1: -+ pci_dev_put(pdev); -+ kfree(device); -+err_kzalloc: -+err_set_dma_mask: -+ pci_release_regions(pdev); -+ pci_disable_device(pdev); -+err_request_regions: -+err_enable_device: -+ dma_err("Probe failed %d\n", err); -+ return err; -+} -+ -+static void __devexit lnw_dma1_remove(struct pci_dev *pdev) -+{ -+ struct lnw_device *device = pci_get_drvdata(pdev); -+ -+ lnwdma_shutdown1(pdev); -+ pci_dev_put(pdev); -+ kfree(device); -+ pci_release_regions(pdev); -+ pci_disable_device(pdev); -+} -+ -+static int __init lnw_dma1_init(void) -+{ -+ dma_info("LNW DMA Driver\n Version %s \n", LNW_DMA_DRIVER_VERSION); -+ return pci_register_driver(&lnw_dma1_pci); -+} -+late_initcall(lnw_dma1_init); -+ -+static void __exit lnw_dma1_exit(void) -+{ -+ pci_unregister_driver(&lnw_dma1_pci); -+} -+module_exit(lnw_dma1_exit); -+ -Index: linux-2.6.33/drivers/dma/lnw_dmac2.c -=================================================================== ---- /dev/null -+++ linux-2.6.33/drivers/dma/lnw_dmac2.c -@@ -0,0 +1,947 @@ -+/* -+ * lnw_dmac2.c - Intel Langwell DMA Drivers -+ * -+ * Copyright (C) 2008-09 Intel Corp -+ * Author: Vinod Koul <vinod.koul@intel.com> -+ * The driver design is based on dw_dmac driver -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * 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., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * -+ */ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/pci.h> -+#include <linux/interrupt.h> -+#include <linux/lnw_dma.h> -+ -+#define MAX_CHAN 2 -+#include "lnw_dma_regs.h" -+ -+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); -+MODULE_DESCRIPTION("Intel (R) Moorestown Langwell DMAC2 Driver"); -+MODULE_LICENSE("GPL v2"); -+MODULE_VERSION(LNW_DMA_DRIVER_VERSION); -+ -+#define DMA_CH0 0 -+#define DMA_CH1 1 -+#define CH_BLOCK_SIZE 2047 -+ -+static int __devinit lnw_dma2_probe(struct pci_dev *pdev, -+ const struct pci_device_id *id); -+static void __devexit lnw_dma2_remove(struct pci_dev *pdev); -+static void enable_dma2_interrupt(struct lnw_dma_chan *lnwc); -+ -+struct lnw_device { -+ struct pci_dev *pdev; -+ void __iomem *dma_base; -+ struct lnwdma_device *dma; -+}; -+ -+/*CH dep code, if ch no's mapping changes only change here*/ -+static int get_ch_id(int index) -+{ -+ if (index == 0) -+ return DMA_CH0; -+ else if (index == 1) -+ return DMA_CH1; -+ else -+ return -1; -+} -+ -+static int get_ch_index(int ch_id) -+{ -+ if (ch_id == DMA_CH0) -+ return 0; -+ if (ch_id == DMA_CH1) -+ return 1; -+ else -+ return -1; -+} -+ -+static int get_ch_num(int *status) -+{ -+ if (*status & (1 << DMA_CH0)) { -+ *status = *status & (~(1 << DMA_CH0)); -+ return DMA_CH0; -+ } else if (*status & (1 << DMA_CH1)) { -+ *status = *status & (~(1 << DMA_CH1)); -+ return DMA_CH1; -+ } else -+ return -1; -+} -+ -+static int get_block_ts(int len, int tx_width) -+{ -+ int byte_width = 0, block_ts = 0; -+ -+ switch (tx_width) { -+ case LNW_DMA_WIDTH_8BIT: -+ byte_width = 1; -+ break; -+ case LNW_DMA_WIDTH_16BIT: -+ byte_width = 2; -+ break; -+ case LNW_DMA_WIDTH_32BIT: -+ default: -+ byte_width = 4; -+ break; -+ } -+ -+ block_ts = len/byte_width; -+ if (block_ts > CH_BLOCK_SIZE) -+ block_ts = 0xFFFF; -+ return block_ts; -+} -+ -+static struct lnw_dma_desc *lnwc_desc_get(struct lnw_dma_chan *lnwc) -+{ -+ struct lnw_dma_desc *desc, *_desc; -+ struct lnw_dma_desc *ret = NULL; -+ -+ dma_dbg("called \n"); -+ spin_lock_bh(&lnwc->lock); -+ list_for_each_entry_safe(desc, _desc, &lnwc->free_list, desc_node) { -+ if (async_tx_test_ack(&desc->txd)) { -+ list_del(&desc->desc_node); -+ ret = desc; -+ dma_dbg("got free desc \n"); -+ break; -+ } -+ } -+ spin_unlock_bh(&lnwc->lock); -+ return ret; -+} -+ -+static void lnwc_desc_put(struct lnw_dma_chan *lnwc, struct lnw_dma_desc *desc) -+{ -+ if (desc) { -+ spin_lock_bh(&lnwc->lock); -+ list_add_tail(&desc->desc_node, &lnwc->free_list); -+ spin_unlock_bh(&lnwc->lock); -+ } -+} -+ -+/* Called with lock held and bh disabled */ -+static void lnwc_dostart(struct lnw_dma_chan *lnwc, struct lnw_dma_desc *first) -+{ -+ struct lnwdma_device *lnw = to_lnwdma_device(lnwc->chan.device); -+ -+ dma_dbg("called \n"); -+ /* channel is idle */ -+ if (lnwc->in_use && test_ch_en(lnwc->dma_base, lnwc->ch_id)) { -+ /*error*/ -+ dma_err("channel is busy \n"); -+ /* The tasklet will hopefully advance the queue... */ -+ return; -+ } -+ -+ /*write registers and en*/ -+ iowrite32(first->sar, lnwc->ch_regs + SAR); -+ iowrite32(first->dar, lnwc->ch_regs + DAR); -+ iowrite32(first->cfg_hi, lnwc->ch_regs + CFG_HIGH); -+ iowrite32(first->cfg_lo, lnwc->ch_regs + CFG_LOW); -+ iowrite32(first->ctl_lo, lnwc->ch_regs + CTL_LOW); -+ iowrite32(first->ctl_hi, lnwc->ch_regs + CTL_HIGH); -+ dma_dbg("TX SAR %lx, DAR %lx, CFGL %x, CFGH %x, CTLH %x, CTLL %x \n", -+ first->sar, first->dar, first->cfg_hi, -+ first->cfg_lo, first->ctl_hi, first->ctl_lo); -+ -+ iowrite32(ENABLE_CHANNEL(lnwc->ch_id), lnw->dma_base + DMA_CHAN_EN); -+ first->status = DMA_IN_PROGRESS; -+} -+ -+static void -+lnwc_descriptor_complete(struct lnw_dma_chan *lnwc, struct lnw_dma_desc *desc) -+{ -+ struct dma_async_tx_descriptor *txd = &desc->txd; -+ dma_async_tx_callback callback = NULL; -+ dma_async_tx_callback callback_txd = NULL; -+ void *param = NULL; -+ void *param_txd = NULL; -+ u32 sar, dar, len; -+ union lnw_dma_ctl_hi ctl_hi; -+ -+ dma_dbg("called \n"); -+ -+ /*check if full tx is complete or not*/ -+ sar = ioread32(lnwc->ch_regs + SAR); -+ dar = ioread32(lnwc->ch_regs + DAR); -+ -+ if (desc->dirn == DMA_FROM_DEVICE) -+ len = dar - desc->dar; -+ else -+ len = sar - desc->sar; -+ -+ dma_dbg("SAR %x DAR %x, DMA done: %x \n", sar, dar, len); -+ if (desc->len > len) { -+ dma_dbg("dirn = %d\n", desc->dirn); -+ dma_dbg("SAR %x DAR %x, len: %x \n", sar, dar, len); -+ /*we have to copy more bytes*/ -+ desc->len -= len; -+ ctl_hi.ctl_hi = desc->ctl_hi; -+ ctl_hi.ctlx.block_ts = get_block_ts(desc->len, desc->width); -+ dma_dbg("setting for %x bytes \n", ctl_hi.ctlx.block_ts); -+ desc->ctl_hi = ctl_hi.ctl_hi; -+ if (desc->cfg_mode == LNW_DMA_MEM_TO_MEM) { -+ sar++; -+ dar++; -+ } else if (desc->dirn == DMA_TO_DEVICE) -+ sar++; -+ else if (desc->dirn == DMA_FROM_DEVICE) -+ dar++; -+ desc->sar = sar; -+ desc->dar = dar; -+ dma_dbg("New SAR %x DAR %x \n", sar, dar); -+ lnwc_dostart(lnwc, desc); -+ return; -+ } -+ -+ lnwc->completed = txd->cookie; -+ callback = desc->callback; -+ param = desc->callback_param; -+ callback_txd = txd->callback; -+ param_txd = txd->callback_param; -+ -+ list_move(&desc->desc_node, &lnwc->free_list); -+ -+ spin_unlock_bh(&lnwc->lock); -+ dma_dbg("Now we are calling callback \n"); -+ if (callback_txd) { -+ dma_dbg("lnw TXD callback set ... calling \n"); -+ callback_txd(param_txd); -+ spin_lock_bh(&lnwc->lock); -+ return; -+ } -+ if (callback) { -+ dma_dbg("lnw callback set ... calling \n"); -+ callback(param); -+ } -+ spin_lock_bh(&lnwc->lock); -+ -+} -+ -+/*check desc, mark as complete when tx is complete*/ -+static void -+lnwc_scan_descriptors(struct lnwdma_device *lnw, struct lnw_dma_chan *lnwc) -+{ -+ struct lnw_dma_desc *desc = NULL, *_desc = NULL; -+ u32 status_xfer; -+ -+ dma_dbg("called \n"); -+ status_xfer = ioread32(lnwc->dma_base + RAW_TFR); -+ status_xfer = (status_xfer >> lnwc->ch_id) & 0x1; -+ dma_dbg("ch[%d]: status_xfer %x \n", lnwc->ch_id, status_xfer); -+ if (!status_xfer) -+ return; -+ -+ /*tx is complete*/ -+ list_for_each_entry_safe(desc, _desc, &lnwc->active_list, desc_node) { -+ if (desc == NULL) -+ continue; -+ if (desc->status == DMA_IN_PROGRESS) { -+ desc->status = DMA_SUCCESS; -+ lnwc_descriptor_complete(lnwc, desc); -+ } -+ } -+ return; -+} -+ -+/***************************************************************************** -+DMA Functions*/ -+static dma_cookie_t lnw_dma2_tx_submit(struct dma_async_tx_descriptor *tx) -+{ -+ struct lnw_dma_desc *desc = to_lnw_dma_desc(tx); -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(tx->chan); -+ dma_cookie_t cookie; -+ -+ dma_dbg("called \n"); -+ -+ spin_lock_bh(&lnwc->lock); -+ cookie = lnwc->chan.cookie; -+ -+ if (++cookie < 0) -+ cookie = 1; -+ -+ lnwc->chan.cookie = cookie; -+ desc->txd.cookie = cookie; -+ -+ if (list_empty(&lnwc->active_list)) { -+ lnwc_dostart(lnwc, desc); -+ list_add_tail(&desc->desc_node, &lnwc->active_list); -+ } else { -+ list_add_tail(&desc->desc_node, &lnwc->queue); -+ } -+ spin_unlock_bh(&lnwc->lock); -+ -+ return cookie; -+} -+ -+static void lnw_dma2_issue_pending(struct dma_chan *chan) -+{ -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(chan); -+ -+ spin_lock_bh(&lnwc->lock); -+ if (!list_empty(&lnwc->queue)) -+ lnwc_scan_descriptors(to_lnwdma_device(chan->device), lnwc); -+ spin_unlock_bh(&lnwc->lock); -+} -+ -+static enum dma_status -+lnw_dma2_tx_is_complete(struct dma_chan *chan, -+ dma_cookie_t cookie, -+ dma_cookie_t *done, -+ dma_cookie_t *used) -+{ -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(chan); -+ dma_cookie_t last_used; -+ dma_cookie_t last_complete; -+ int ret; -+ -+ last_complete = lnwc->completed; -+ last_used = chan->cookie; -+ -+ ret = dma_async_is_complete(cookie, last_complete, last_used); -+ if (ret != DMA_SUCCESS) { -+ lnwc_scan_descriptors(to_lnwdma_device(chan->device), lnwc); -+ -+ last_complete = lnwc->completed; -+ last_used = chan->cookie; -+ -+ ret = dma_async_is_complete(cookie, last_complete, last_used); -+ } -+ -+ if (done) -+ *done = last_complete; -+ if (used) -+ *used = last_used; -+ -+ return ret; -+} -+ -+static void lnw_dma2_terminate_all(struct dma_chan *chan) -+{ -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(chan); -+ struct lnwdma_device *lnw = to_lnwdma_device(chan->device); -+ struct lnw_dma_desc *desc, *_desc; -+ LIST_HEAD(list); -+ -+ /* ASSERT: channel is idle */ -+ if (lnwc->in_use == false) { -+ /*ch is not in use, wrong call*/ -+ return; -+ } -+ spin_lock_bh(&lnwc->lock); -+ list_splice_init(&lnwc->free_list, &list); -+ lnwc->descs_allocated = 0; -+ lnwc->slave = NULL; -+ -+ /* Disable interrupts*/ -+ iowrite32(MASK_INTR_REG(lnwc->ch_id), lnw->dma_base + MASK_BLOCK); -+ iowrite32(MASK_INTR_REG(lnwc->ch_id), lnw->dma_base + MASK_ERR); -+ -+ spin_unlock_bh(&lnwc->lock); -+ list_for_each_entry_safe(desc, _desc, &list, desc_node) { -+ dma_dbg("freeing descriptor %p\n", desc); -+ pci_pool_free(lnw->dma_pool, desc, desc->txd.phys); -+ } -+ -+ return; -+} -+ -+static struct dma_async_tx_descriptor * -+lnw_dma2_prep_slave_sg(struct dma_chan *chan, -+ struct scatterlist *sgl, unsigned int sg_len, -+ enum dma_data_direction direction, -+ unsigned long flags) -+{ -+ /*not supported now*/ -+ return NULL; -+} -+ -+static struct dma_async_tx_descriptor * -+lnw_dma2_prep_memcpy(struct dma_chan *chan, dma_addr_t dest, -+ dma_addr_t src, size_t len, unsigned long flags) -+{ -+ struct lnw_dma_chan *lnwc; -+ struct lnw_dma_desc *desc = NULL; -+ struct lnw_dma_slave *lnws; -+ union lnw_dma_ctl_lo ctl_lo; -+ union lnw_dma_ctl_hi ctl_hi; -+ union lnw_dma_cfg_lo cfg_lo; -+ union lnw_dma_cfg_hi cfg_hi; -+ enum lnw_dma_width width = 0; -+ -+ dma_dbg("called \n"); -+ WARN_ON(!chan); -+ if (!len) -+ return NULL; -+ -+ lnws = chan->private; -+ WARN_ON(!lnws); -+ -+ lnwc = to_lnw_dma_chan(chan); -+ WARN_ON(!lnwc); -+ -+ dma_dbg("called for CH %d\n", lnwc->ch_id); -+ dma_dbg("Cfg passed Mode %x, Dirn %x, HS %x, Width %x \n", -+ lnws->cfg_mode, lnws->dirn, lnws->hs_mode, lnws->src_width); -+ -+ /*calculate CFG_LO*/ -+ if (lnws->hs_mode == LNW_DMA_SW_HS) { -+ cfg_lo.cfg_lo = 0; -+ cfg_lo.cfgx.hs_sel_dst = 1; -+ cfg_lo.cfgx.hs_sel_src = 1; -+ } else if (lnws->hs_mode == LNW_DMA_HW_HS) -+ cfg_lo.cfg_lo = 0x00000; -+ -+ /*calculate CFG_HI*/ -+ if (lnws->cfg_mode == LNW_DMA_MEM_TO_MEM) { -+ /*SW HS only*/ -+ dma_dbg("CFG: Mem to mem dma \n"); -+ cfg_hi.cfg_hi = 0; -+ } else { -+ dma_dbg("HW DMA \n"); -+ cfg_hi.cfg_hi = 0; -+ cfg_hi.cfgx.protctl = 0x1; /*default value*/ -+ cfg_hi.cfgx.src_per = get_ch_index(lnwc->ch_id); -+ cfg_hi.cfgx.dst_per = get_ch_index(lnwc->ch_id); -+ } -+ -+ /*calculate CTL_HI*/ -+ ctl_hi.ctlx.reser = 0; -+ width = lnws->src_width; -+ ctl_hi.ctlx.block_ts = get_block_ts(len, width); -+ -+ /*calculate CTL_LO*/ -+ ctl_lo.ctl_lo = 0; -+ ctl_lo.ctlx.int_en = 1; -+ ctl_lo.ctlx.dst_tr_width = lnws->dst_width; -+ ctl_lo.ctlx.src_tr_width = lnws->src_width; -+ ctl_lo.ctlx.dst_msize = lnws->src_msize; -+ ctl_lo.ctlx.src_msize = lnws->dst_msize; -+ -+ if (lnws->cfg_mode == LNW_DMA_MEM_TO_MEM) { -+ dma_dbg("CTL: Mem to mem dma \n"); -+ ctl_lo.ctlx.tt_fc = 0; -+ ctl_lo.ctlx.sinc = 0; -+ ctl_lo.ctlx.dinc = 0; -+ } else { -+ if (lnws->dirn == DMA_TO_DEVICE) { -+ dma_dbg("CTL: DMA_TO_DEVICE \n"); -+ ctl_lo.ctlx.sinc = 0; -+ ctl_lo.ctlx.dinc = 2; -+ ctl_lo.ctlx.tt_fc = 1; -+ } else if (lnws->dirn == DMA_FROM_DEVICE) { -+ dma_dbg("CTL: DMA_FROM_DEVICE \n"); -+ ctl_lo.ctlx.sinc = 2; -+ ctl_lo.ctlx.dinc = 0; -+ ctl_lo.ctlx.tt_fc = 2; -+ } -+ } -+ -+ dma_dbg("Calc CTL LO %x, CTL HI %x, CFG LO %x, CFG HI %x\n", -+ ctl_lo.ctl_lo, ctl_hi.ctl_hi, cfg_lo.cfg_lo, cfg_hi.cfg_hi); -+ -+ enable_dma2_interrupt(lnwc); -+ -+ desc = lnwc_desc_get(lnwc); -+ if (desc == NULL) -+ goto err_desc_get; -+ desc->sar = src; -+ desc->dar = dest ; -+ desc->len = len; -+ desc->cfg_hi = cfg_hi.cfg_hi; -+ desc->cfg_lo = cfg_lo.cfg_lo; -+ desc->ctl_lo = ctl_lo.ctl_lo; -+ desc->ctl_hi = ctl_hi.ctl_hi; -+ desc->width = width; -+ desc->dirn = lnws->dirn; -+ if (lnws->callback) { -+ desc->callback = lnws->callback; -+ desc->callback_param = lnws->callback_param; -+ dma_dbg("Callback passed... setting\n"); -+ } else -+ desc->callback = NULL; -+ return &desc->txd; -+ -+err_desc_get: -+ dma_err("Failed to get desc \n"); -+ lnwc_desc_put(lnwc, desc); -+ return NULL; -+} -+ -+ -+static void lnw_dma2_free_chan_resources(struct dma_chan *chan) -+{ -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(chan); -+ struct lnwdma_device *lnw = to_lnwdma_device(chan->device); -+ struct lnw_dma_desc *desc, *_desc; -+ -+ dma_dbg("..called for ch_id %d, lnwch_id %d\n", -+ chan->chan_id, lnwc->ch_id); -+ if (true == lnwc->in_use) { -+ /*trying to free ch in use!!!!!*/ -+ dma_err("trying to free ch in use \n"); -+ } -+ -+ spin_lock_bh(&lnwc->lock); -+ lnwc->descs_allocated = 0; -+ list_for_each_entry_safe(desc, _desc, &lnwc->active_list, desc_node) { -+ dma_dbg("del active \n"); -+ list_del(&desc->desc_node); -+ pci_pool_free(lnw->dma_pool, desc, desc->txd.phys); -+ } -+ list_for_each_entry_safe(desc, _desc, &lnwc->free_list, desc_node) { -+ list_del(&desc->desc_node); -+ pci_pool_free(lnw->dma_pool, desc, desc->txd.phys); -+ } -+ list_for_each_entry_safe(desc, _desc, &lnwc->queue, desc_node) { -+ dma_dbg("del queue \n"); -+ list_del(&desc->desc_node); -+ pci_pool_free(lnw->dma_pool, desc, desc->txd.phys); -+ } -+ spin_unlock_bh(&lnwc->lock); -+ lnwc->in_use = false; -+ chan->client_count--; -+ /* Disable CH interrupts*/ -+ iowrite32(MASK_INTR_REG(lnwc->ch_id), lnw->dma_base + MASK_BLOCK); -+ iowrite32(MASK_INTR_REG(lnwc->ch_id), lnw->dma_base + MASK_ERR); -+ dma_dbg("done \n"); -+} -+ -+static int lnw_dma2_alloc_chan_resources(struct dma_chan *chan) -+{ -+ struct lnw_dma_chan *lnwc = to_lnw_dma_chan(chan); -+ struct lnwdma_device *lnw = to_lnwdma_device(chan->device); -+ struct lnw_dma_desc *desc; -+ dma_addr_t phys; -+ int i = 0; -+ -+ dma_dbg("called \n"); -+ -+ /* ASSERT: channel is idle */ -+ if (test_ch_en(lnw->dma_base, lnwc->ch_id)) { -+ /*ch is not idle*/ -+ dma_err(".ch not idle\n"); -+ return -EIO; -+ } -+ dma_dbg("..called for ch_id %d, lnwch_id %d\n", -+ chan->chan_id, lnwc->ch_id); -+ lnwc->completed = chan->cookie = 1; -+ -+ chan->client_count++; -+ -+ spin_lock_bh(&lnwc->lock); -+ while (lnwc->descs_allocated < DESCS_PER_CHANNEL) { -+ spin_unlock_bh(&lnwc->lock); -+ desc = pci_pool_alloc(lnw->dma_pool, GFP_KERNEL, &phys); -+ if (!desc) { -+ dma_err("desc failed\n"); -+ return -ENOMEM; -+ /*check*/ -+ } -+ dma_async_tx_descriptor_init(&desc->txd, chan); -+ desc->txd.tx_submit = lnw_dma2_tx_submit; -+ desc->txd.flags = DMA_CTRL_ACK; -+ desc->txd.phys = phys; -+ spin_lock_bh(&lnwc->lock); -+ i = ++lnwc->descs_allocated; -+ list_add_tail(&desc->desc_node, &lnwc->free_list); -+ } -+ spin_unlock_bh(&lnwc->lock); -+ lnwc->in_use = false; -+ dma_dbg("Desc alloc done ret: %d desc\n", i); -+ return i; -+} -+ -+static void lnwc_handle_error(struct lnwdma_device *lnw, -+ struct lnw_dma_chan *lnwc) -+{ -+ lnwc_scan_descriptors(lnw, lnwc); -+} -+ -+/****************************************************************************** -+* PCI stuff -+*/ -+static struct pci_device_id lnw_dma2_ids[] = { -+ { PCI_VENDOR_ID_INTEL, 0x0813, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -+ { 0, } -+}; -+ -+MODULE_DEVICE_TABLE(pci, lnw_dma2_ids); -+ -+static struct pci_driver lnw_dma2_pci = { -+ .name = "Intel LNW DMA2", -+ .id_table = lnw_dma2_ids, -+ .probe = lnw_dma2_probe, -+ .remove = __devexit_p(lnw_dma2_remove), -+}; -+ -+static void dma_tasklet(unsigned long data) -+{ -+ struct lnwdma_device *lnw = NULL; -+ struct lnw_dma_chan *lnwc = NULL; -+ u32 status; -+ int i, ch_no; -+ -+ dma_dbg("called \n"); -+ lnw = (struct lnwdma_device *)data; -+ if (lnw == NULL) { -+ dma_err("Null param \n"); -+ return; -+ } -+ -+ status = ioread32(lnw->dma_base + RAW_TFR); -+ dma_dbg("RAW_TFR %x \n", status); -+ while (status) { -+ /*txn interrupt*/ -+ ch_no = get_ch_num(&status); -+ if (ch_no < 0) { -+ dma_err("Ch no is invalid %x, abort!\n", ch_no); -+ return; -+ } -+ dma_dbg("Got Ch %x, new Status %x \n", ch_no, status); -+ i = get_ch_index(ch_no); -+ if (i < 0) { -+ dma_err("Invalid ch index %x\n", i); -+ return; -+ } -+ dma_dbg("Tx complete interrupt %x, Ch No %d Index %d \n", -+ status, ch_no, i); -+ lnwc = &lnw->ch[i]; -+ if (lnwc == NULL) { -+ dma_err("Null param lnwc\n"); -+ return; -+ } -+ dma_dbg("CH %x \n", lnwc->ch_id); -+ spin_lock_bh(&lnwc->lock); -+ lnwc_scan_descriptors(lnw, lnwc); -+ dma_dbg("Scan of desc... complete, unmasking\n"); -+ iowrite32((1 << lnwc->ch_id), -+ lnw->dma_base + CLEAR_TFR); -+ dma_dbg("Wrote to clear %x\n", (1 << lnwc->ch_id)); -+ iowrite32((1 << lnwc->ch_id), -+ lnw->dma_base + CLEAR_BLOCK); -+ iowrite32(UNMASK_INTR_REG(lnwc->ch_id), -+ lnw->dma_base + MASK_TFR); -+ spin_unlock_bh(&lnwc->lock); -+ } -+ -+ dma_dbg("Trf interrupt done... \n"); -+ status = ioread32(lnw->dma_base + RAW_ERR); -+ while (status) { -+ /*err interrupt*/ -+ ch_no = get_ch_num(&status); -+ if (ch_no < 0) { -+ dma_err("Ch no is invalid %x, abort!\n", ch_no); -+ return; -+ } -+ dma_dbg("Got Ch %x, new Status %x \n", ch_no, status); -+ i = get_ch_index(ch_no); -+ if (i < 0) { -+ dma_err("Invalid CH lnwc\n"); -+ return; -+ } -+ dma_dbg("Tx error interrupt %x, No %d Index %d \n", -+ status, ch_no, i); -+ lnwc = &lnw->ch[i]; -+ if (lnwc == NULL) { -+ dma_err("Null param lnwc\n"); -+ return; -+ } -+ spin_lock_bh(&lnwc->lock); -+ lnwc_handle_error(lnw, lnwc); -+ iowrite32((1 << lnwc->ch_id), -+ lnw->dma_base + CLEAR_ERR); -+ iowrite32(UNMASK_INTR_REG(lnwc->ch_id), -+ lnw->dma_base + MASK_ERR); -+ spin_unlock_bh(&lnwc->lock); -+ } -+ dma_dbg("Exiting takslet... \n"); -+ return; -+} -+ -+static irqreturn_t lnw_dma2_interrupt(int irq, void *data) -+{ -+ struct lnw_device *lnw = data; -+ u32 status; -+ int call_tasklet = 0; -+ -+ /*will mask interrupt for now and schedule tasklet -+ tasklet shud unmask and clear*/ -+ status = ioread32(lnw->dma_base + STATUS_TFR); -+ status &= 0x03; -+ if (status) { -+ iowrite32((status << 8), lnw->dma_base + MASK_TFR); -+ call_tasklet = 1; -+ } -+ status = ioread32(lnw->dma_base + STATUS_ERR); -+ status &= 0x03; -+ if (status) { -+ iowrite32(MASK_INTR_REG(status), lnw->dma_base + MASK_ERR); -+ call_tasklet = 1; -+ } -+ -+ if (call_tasklet) -+ tasklet_schedule(&lnw->dma->tasklet); -+ -+ return IRQ_HANDLED; -+} -+ -+static void enable_dma2_interrupt(struct lnw_dma_chan *lnwc) -+{ -+ dma_dbg("Called for ch_id %d\n", lnwc->ch_id); -+ -+ iowrite32(REG_BIT0, lnwc->dma->dma_base + DMA_CFG); -+ /*en ch interrupts */ -+ iowrite32(UNMASK_INTR_REG(lnwc->ch_id), lnwc->dma_base + MASK_TFR); -+ iowrite32(UNMASK_INTR_REG(lnwc->ch_id), lnwc->dma_base + MASK_ERR); -+ return; -+} -+ -+static void disable_dma2_interrupt(struct lnw_device *device) -+{ -+ u32 status = 0; -+ -+ /*todo*/ -+ dma_dbg(" called \n"); -+ status = 1; -+ return; -+ -+} -+ -+static int lnw_setup_dma2(struct pci_dev *pdev) -+{ -+ struct lnw_device *device = pci_get_drvdata(pdev); -+ struct lnwdma_device *dma = NULL; -+ int err, i; -+ -+ dma_dbg("setup_dma called \n"); -+ dma = kzalloc(sizeof(*dma), GFP_KERNEL); -+ if (NULL == dma) { -+ dma_err("kzalloc failed \n"); -+ err = -ENOMEM; -+ goto err_kzalloc; -+ } -+ device->dma = dma; -+ dma->pdev = pdev; -+ dma->dma_base = device->dma_base; -+ -+ /* DMA coherent memory pool for DMA descriptor allocations */ -+ dma->dma_pool = pci_pool_create("dma_desc_pool", pdev, -+ sizeof(struct lnw_dma_desc), -+ 32, 0); -+ if (NULL == dma->dma_pool) { -+ dma_err("pci_pool_create failed \n"); -+ err = -ENOMEM; -+ kfree(dma); -+ goto err_dma_pool; -+ } -+ -+ INIT_LIST_HEAD(&dma->common.channels); -+ -+ -+ /*init CH structures*/ -+ for (i = 0; i < MAX_CHAN; i++) { -+ struct lnw_dma_chan *lnwch = &dma->ch[i]; -+ -+ lnwch->chan.device = &dma->common; -+ lnwch->chan.cookie = 1; -+ lnwch->chan.chan_id = i; -+ lnwch->ch_id = get_ch_id(i); -+ dma_dbg("Init CH %d, ID %d \n", i, lnwch->ch_id); -+ -+ lnwch->dma_base = dma->dma_base; -+ lnwch->ch_regs = dma->dma_base + DMA_CH_SIZE * lnwch->ch_id; -+ lnwch->dma = dma; -+ spin_lock_init(&lnwch->lock); -+ -+ INIT_LIST_HEAD(&lnwch->active_list); -+ INIT_LIST_HEAD(&lnwch->queue); -+ INIT_LIST_HEAD(&lnwch->free_list); -+ -+ /*mask interrupts*/ -+ iowrite32(MASK_INTR_REG(lnwch->ch_id), -+ dma->dma_base + MASK_BLOCK); -+ iowrite32(MASK_INTR_REG(lnwch->ch_id), -+ dma->dma_base + MASK_SRC_TRAN); -+ iowrite32(MASK_INTR_REG(lnwch->ch_id), -+ dma->dma_base + MASK_DST_TRAN); -+ iowrite32(MASK_INTR_REG(lnwch->ch_id), -+ dma->dma_base + MASK_ERR); -+ iowrite32(MASK_INTR_REG(lnwch->ch_id), -+ dma->dma_base + MASK_TFR); -+ -+ dma_dbg("Init CH %d, ID %d \n", i, lnwch->ch_id); -+ list_add_tail(&lnwch->chan.device_node, &dma->common.channels); -+ } -+ -+ /*init dma structure*/ -+ dma_cap_zero(dma->common.cap_mask); -+ dma_cap_set(DMA_MEMCPY, dma->common.cap_mask); -+ dma_cap_set(DMA_SLAVE, dma->common.cap_mask); -+ dma_cap_set(DMA_PRIVATE, dma->common.cap_mask); -+ dma->common.dev = &pdev->dev; -+ dma->common.chancnt = MAX_CHAN; -+ -+ dma->common.device_alloc_chan_resources = -+ lnw_dma2_alloc_chan_resources; -+ dma->common.device_free_chan_resources = -+ lnw_dma2_free_chan_resources; -+ -+ dma->common.device_is_tx_complete = lnw_dma2_tx_is_complete; -+ dma->common.device_prep_dma_memcpy = lnw_dma2_prep_memcpy; -+ dma->common.device_issue_pending = lnw_dma2_issue_pending; -+ dma->common.device_prep_slave_sg = lnw_dma2_prep_slave_sg; -+ dma->common.device_terminate_all = lnw_dma2_terminate_all; -+ -+ /*enable dma cntrl*/ -+ iowrite32(REG_BIT0, dma->dma_base + DMA_CFG); -+ -+ disable_dma2_interrupt(device); -+ -+ /*register irq*/ -+ err = request_irq(pdev->irq, lnw_dma2_interrupt, -+ 0, lnw_dma2_pci.name, device); -+ if (0 != err) -+ goto err_irq; -+ -+ /*register device w/ engine*/ -+ err = dma_async_device_register(&dma->common); -+ if (0 != err) { -+ dma_err("device_register failed: %d \n", err); -+ goto err_engine; -+ } -+ tasklet_init(&dma->tasklet, dma_tasklet, (unsigned long)dma); -+ dma_dbg("...done\n"); -+ return 0; -+ -+err_engine: -+ free_irq(pdev->irq, device); -+err_irq: -+ pci_pool_destroy(dma->dma_pool); -+ kfree(dma); -+err_dma_pool: -+err_kzalloc: -+ dma_err("setup_dma failed: %d \n", err); -+ return err; -+ -+} -+ -+static void lnwdma_shutdown(struct pci_dev *pdev) -+{ -+ struct lnw_device *device = pci_get_drvdata(pdev); -+ -+ dma_dbg("shutdown called \n"); -+ dma_async_device_unregister(&device->dma->common); -+ pci_pool_destroy(device->dma->dma_pool); -+ if (device->dma_base) -+ iounmap(device->dma_base); -+ free_irq(pdev->irq, device); -+ return; -+} -+static int __devinit -+lnw_dma2_probe(struct pci_dev *pdev, const struct pci_device_id *id) -+{ -+ struct lnw_device *device = NULL; -+ u32 base_addr = 0, bar_size = 0; -+ int err = 0; -+ -+ dma_info("probe called for %x \n", pdev->device); -+ err = pci_enable_device(pdev); -+ if (err) -+ goto err_enable_device; -+ -+ err = pci_request_regions(pdev, lnw_dma2_pci.name); -+ if (err) -+ goto err_request_regions; -+ -+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); -+ if (err) -+ goto err_set_dma_mask; -+ -+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); -+ if (err) -+ goto err_set_dma_mask; -+ -+ device = kzalloc(sizeof(*device), GFP_KERNEL); -+ if (!device) { -+ dma_err("kzalloc failed \n"); -+ err = -ENOMEM; -+ goto err_kzalloc; -+ } -+ device->pdev = pci_dev_get(pdev); -+ -+ base_addr = pci_resource_start(pdev, 0); -+ bar_size = pci_resource_len(pdev, 0); -+ dma_dbg("BAR0 %x Size %x \n", base_addr, bar_size); -+ device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE); -+ if (!device->dma_base) { -+ dma_err("ioremap failed \n"); -+ err = -ENOMEM; -+ goto err_ioremap; -+ } -+ -+ pci_set_drvdata(pdev, device); -+ pci_set_master(pdev); -+ -+ err = lnw_setup_dma2(pdev); -+ if (err) -+ goto err_dma; -+ -+ return 0; -+ -+err_dma: -+ iounmap(device->dma_base); -+err_ioremap: -+ pci_dev_put(pdev); -+ kfree(device); -+err_kzalloc: -+err_set_dma_mask: -+ pci_release_regions(pdev); -+ pci_disable_device(pdev); -+err_request_regions: -+err_enable_device: -+ dma_err("Probe failed %d\n", err); -+ return err; -+} -+ -+static void __devexit lnw_dma2_remove(struct pci_dev *pdev) -+{ -+ struct lnw_device *device = pci_get_drvdata(pdev); -+ -+ lnwdma_shutdown(pdev); -+ pci_dev_put(pdev); -+ kfree(device); -+ pci_release_regions(pdev); -+ pci_disable_device(pdev); -+} -+ -+static int __init lnw_dma2_init(void) -+{ -+ dma_info("LNW DMA Driver\n Version %s \n", LNW_DMA_DRIVER_VERSION); -+ return pci_register_driver(&lnw_dma2_pci); -+} -+fs_initcall(lnw_dma2_init); -+ -+static void __exit lnw_dma2_exit(void) -+{ -+ pci_unregister_driver(&lnw_dma2_pci); -+} -+module_exit(lnw_dma2_exit); -+ -Index: linux-2.6.33/include/linux/lnw_dma.h -=================================================================== ---- /dev/null -+++ linux-2.6.33/include/linux/lnw_dma.h -@@ -0,0 +1,166 @@ -+/* -+ * lnw_dma.c - Intel Langwell DMA Drivers -+ * -+ * Copyright (C) 2008i-09 Intel Corp -+ * Author: Vinod Koul <vinod.koul@intel.com> -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * 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., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * -+ */ -+#ifndef __LNW_DMA_H__ -+#define __LNW_DMA_H__ -+ -+#include <linux/dmaengine.h> -+ -+/*DMA transaction width, src and dstn width would be same -+The DMA length must be width aligned, -+for 32 bit width the length must be 32 bit (4bytes) aligned only*/ -+enum lnw_dma_width { -+ LNW_DMA_WIDTH_8BIT = 0x0, -+ LNW_DMA_WIDTH_16BIT = 0x1, -+ LNW_DMA_WIDTH_32BIT = 0x2, -+}; -+ -+/*DMA mode configurations*/ -+enum lnw_dma_mode { -+ LNW_DMA_PER_TO_MEM = 0, /*periphral to memory configuration*/ -+ LNW_DMA_MEM_TO_PER, /*memory to periphral configuration*/ -+ LNW_DMA_MEM_TO_MEM, /*mem to mem confg (testing only)*/ -+}; -+ -+/*DMA handshaking*/ -+enum lnw_dma_hs_mode { -+ LNW_DMA_HW_HS = 0, /*HW Handshaking only*/ -+ LNW_DMA_SW_HS = 1, /*SW Handshaking not recommended*/ -+}; -+ -+/*Burst size configuration*/ -+enum lnw_dma_msize { -+ LNW_DMA_MSIZE_1 = 0x0, -+ LNW_DMA_MSIZE_4 = 0x1, -+ LNW_DMA_MSIZE_8 = 0x2, -+ LNW_DMA_MSIZE_16 = 0x3, -+ LNW_DMA_MSIZE_32 = 0x4, -+ LNW_DMA_MSIZE_64 = 0x5, -+}; -+ -+/** -+ * struct lnw_dma_slave - DMA slave structure -+ * -+ * @dma_dev: DMA master client -+ * @tx_reg: physical address of data register used for -+ * memory-to-peripheral transfers -+ * @rx_reg: physical address of data register used for -+ * peripheral-to-memory transfers -+ * @tx_width: tx register width -+ * @rx_width: rx register width -+ * @dirn: DMA trf direction -+ -+ * @cfg_hi: Platform-specific initializer for the CFG_HI register -+ * @cfg_lo: Platform-specific initializer for the CFG_LO register -+ -+ * @ tx_width: width of src and dstn -+ * @ hs_mode: SW or HW handskaking mode -+ * @ cfg_mode: Mode configuration, DMA mem to mem to dev & mem -+ */ -+struct lnw_dma_slave { -+ enum dma_data_direction dirn; -+ enum lnw_dma_width src_width; /*width of DMA src txn*/ -+ enum lnw_dma_width dst_width; /*width of DMA dst txn*/ -+ enum lnw_dma_hs_mode hs_mode; /*handshaking*/ -+ enum lnw_dma_mode cfg_mode; /*mode configuration*/ -+ enum lnw_dma_msize src_msize; /*size if src burst*/ -+ enum lnw_dma_msize dst_msize; /*size of dst burst*/ -+ dma_async_tx_callback callback; /*callback function*/ -+ void *callback_param; /*param for callback*/ -+}; -+ -+/*DMA channel control registers*/ -+union lnw_dma_ctl_lo { -+ struct { -+ u32 int_en:1; /*enable or disable interrupts*/ -+ /*should be 0*/ -+ u32 dst_tr_width:3; /*destination transfer width*/ -+ /*usually 32 bits = 010*/ -+ u32 src_tr_width:3; /*source transfer width*/ -+ /*usually 32 bits = 010*/ -+ u32 dinc:2; /*destination address inc/dec*/ -+ /*For mem:INC=00, Periphral NoINC=11*/ -+ u32 sinc:2; /*source address inc or dec, as above*/ -+ u32 dst_msize:3; /*destination burst transaction length*/ -+ /*always = 16 ie 011*/ -+ u32 src_msize:3; /*source burst transaction length*/ -+ /*always = 16 ie 011*/ -+ u32 reser1:3; -+ u32 tt_fc:3; /*transfer type and flow controller*/ -+ /*M-M = 000 -+ P-M = 010 -+ M-P = 001*/ -+ u32 dms:2; /*destination master select = 0*/ -+ u32 sms:2; /*source master select = 0*/ -+ u32 llp_dst_en:1; /*enable/disable destination LLP = 0*/ -+ u32 llp_src_en:1; /*enable/disable source LLP = 0*/ -+ u32 reser2:3; -+ } ctlx; -+ u32 ctl_lo; -+}; -+ -+union lnw_dma_ctl_hi { -+ struct { -+ u32 block_ts:12; /*block transfer size*/ -+ /*configured by DMAC*/ -+ u32 reser:20; -+ } ctlx; -+ u32 ctl_hi; -+ -+}; -+ -+/*DMA channel configuration registers*/ -+union lnw_dma_cfg_lo { -+ struct { -+ u32 reser1:5; -+ u32 ch_prior:3; /*channel priority = 0*/ -+ u32 ch_susp:1; /*channel suspend = 0*/ -+ u32 fifo_empty:1; /*FIFO empty or not R bit = 0*/ -+ u32 hs_sel_dst:1; /*select HW/SW destn handshaking*/ -+ /*HW = 0, SW = 1*/ -+ u32 hs_sel_src:1; /*select HW/SW src handshaking*/ -+ u32 reser2:6; -+ u32 dst_hs_pol:1; /*dest HS interface polarity*/ -+ u32 src_hs_pol:1; /*src HS interface polarity*/ -+ u32 max_abrst:10; /*max AMBA burst len = 0 (no sw limit*/ -+ u32 reload_src:1; /*auto reload src addr =1 if src is P*/ -+ u32 reload_dst:1; /*AR destn addr =1 if dstn is P*/ -+ } cfgx; -+ u32 cfg_lo; -+}; -+ -+union lnw_dma_cfg_hi { -+ struct { -+ u32 fcmode:1; /*flow control mode = 1*/ -+ u32 fifo_mode:1; /*FIFO mode select = 1*/ -+ u32 protctl:3; /*protection control = 0*/ -+ u32 rsvd:2; -+ u32 src_per:4; /*src hw HS interface*/ -+ u32 dst_per:4; /*dstn hw HS interface*/ -+ u32 reser2:17; -+ } cfgx; -+ u32 cfg_hi; -+}; -+ -+#endif /*__LNW_DMA_H__*/ -Index: linux-2.6.33/include/linux/intel_mid.h -=================================================================== ---- /dev/null -+++ linux-2.6.33/include/linux/intel_mid.h -@@ -0,0 +1,144 @@ -+/* -+ * intel_mid.h - Netlink multicast interface definition for OSPM. -+ * -+ * Copyright (C) 2009 Intel Corp -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; version 2 of the License. -+ * -+ * 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., -+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -+ * -+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+ * Authors: Sujith Thomas -+ * Rajeev D Muralidhar -+ * Vishwesh M Rudramuni -+ * Nithish Mahalingam -+ * Contact information: -+ * Sujith Thomas <sujith.thomas@intel.com> -+ * Rajeev D Muralidhar <rajeev.d.muralidhar@intel.com> -+ * Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com> -+ * Nithish Mahalingam <nithish.mahalingam@intel.com> -+ * -+ */ -+ -+#ifndef INTEL_MID_H -+#define INTEL_MID_H -+ -+#define PMU1_MAX_DEVS 2 -+#define PMU2_MAX_DEVS 12 -+#define PERIPH_MAX_DEVS 3 -+#define MAX_DEVICES (PMU1_MAX_DEVS + PMU2_MAX_DEVS + PERIPH_MAX_DEVS) -+#define WAKE_CAPABLE 0x80000000 -+ -+struct pci_dev_info { -+ u16 vendor_id; -+ u16 device_id; -+ u16 log_subsysid; -+ u16 phy_susbsysid; -+ u32 capability; -+ struct pci_dev *dev_driver; -+ char *dev_name; -+}; -+ -+struct mid_ospm { -+ u32 *pmu1_base; -+ u32 *pmu1_pm_base; -+ void __iomem *pmu2_base; -+ u32 *pm_table_base; -+ u32 pmu1_sub_systems; -+ u32 pmu2_sub_systems; -+ u32 pmu_wake_cfg; -+ u32 pmu_wake_ss_states; -+ u32 perepheral_sub_systems; -+ int pmu2_states; -+ int platform_sx_state; -+ int s0ix_retry_enb; -+ int fast_retry_exit; -+ u32 pmode; -+}; -+ -+extern struct pci_dev_info platform_pci_devices[MAX_DEVICES]; -+extern unsigned long g_intel_mid_wakeup_address; -+ -+enum pmu_ss_state { -+ SS_STATE_D0I0 = 0, -+ SS_STATE_D0I1 = 1, -+ SS_STATE_D0I2 = 2, -+ SS_STATE_D0I3 = 3 -+}; -+ -+enum eospm_events { -+ OSPM_EVENT_SUBSYS_INACTIVITY, -+ OSPM_EVENT_SUBSYS_WAKE, -+ OSPM_EVENT_SUBSYS_START_PLAY, -+ OSPM_EVENT_SUBSYS_STOP_PLAY, -+ OSPM_EVENT_CMD_SUCCESS, -+ OSPM_EVENT_CMD_ERROR, -+ OSPM_EVENT_CMD_NO_C6_ERROR, -+ OSPM_EVENT_AUDIO_BUF_EMPTY, -+ OSPM_EVENT_AUDIO_BUF_FULL, -+ OSPM_EVENT_THERMAL_AUX0, -+ OSPM_EVENT_THERMAL_AUX1, -+ OSPM_EVENT_THERMAL_CRITICAL, -+ OSPM_EVENT_THERMAL_DEV_FAULT, -+ __OSPM_EVENT_COUNT, -+}; -+ -+#define AUDIO_SUBSYTEM_ID 25 -+#define MID_S0I1_STATE 1 -+#define MID_S0I3_STATE 3 -+/* Thermal device Id */ -+#define TEMP_DEV_ID1 40 -+#define TEMP_DEV_ID2 41 -+#define TEMP_DEV_ID3 42 -+ -+/* First 32 (0-31) originators are subsystems -+ Next 8 (0-7) are cmd IDs */ -+#define OSPM_CMDID_OFFSET 32 -+#define OSPM_MAX_CMD_ID 8 -+ -+struct ospm_genl_event { -+ u32 orig; -+ enum eospm_events event; -+}; -+ -+/* attributes of ospm_genl_family */ -+enum { -+ OSPM_GENL_ATTR_UNSPEC, -+ OSPM_GENL_ATTR_EVENT, /* OSPM event info needed by user space */ -+ __OSPM_GENL_ATTR_MAX, -+}; -+#define OSPM_GENL_ATTR_MAX (__OSPM_GENL_ATTR_MAX - 1) -+ -+/* commands supported by the ospm_genl_family */ -+ -+enum { -+ OSPM_GENL_CMD_UNSPEC, -+ OSPM_GENL_CMD_EVENT, /* kernel->user notifications for OSPM events */ -+ __OSPM_GENL_CMD_MAX, -+}; -+#define OSPM_GENL_CMD_MAX (__OSPM_GENL_CMD_MAX - 1) -+ -+#define OSPM_GENL_FAMILY_NAME "ospm_event" -+#define OSPM_GENL_VERSION 0x01 -+#define OSPM_GENL_MCAST_GROUP_NAME "ospm_mc_group" -+ -+int ospm_generate_netlink_event(u32 orig, enum eospm_events event); -+int ospm_event_genetlink_init(void); -+void ospm_event_genetlink_exit(void); -+ -+extern void intel_mid_reserve_bootmem(void); -+extern unsigned long g_intel_mid_wakeup_address; -+extern void find_pci_info(u32 device_id, u32 vendor_id, u32 *index); -+extern int s0ix_non_bsp_init(void); -+ -+#endif |