summaryrefslogtreecommitdiffstats
path: root/driver/hdm-dim2
diff options
context:
space:
mode:
Diffstat (limited to 'driver/hdm-dim2')
-rw-r--r--driver/hdm-dim2/Makefile18
-rw-r--r--driver/hdm-dim2/dim2_hal.c33
-rw-r--r--driver/hdm-dim2/dim2_hdm.c105
-rw-r--r--driver/hdm-dim2/dim2_hdm.h9
-rw-r--r--driver/hdm-dim2/dim2_reg.h1
5 files changed, 78 insertions, 88 deletions
diff --git a/driver/hdm-dim2/Makefile b/driver/hdm-dim2/Makefile
deleted file mode 100644
index 8ffaa23..0000000
--- a/driver/hdm-dim2/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-# Makefile
-#
-
-SRC := $(shell pwd)
-
-obj-m += hdm_dim2.o
-hdm_dim2-y := dim2_hdm.o dim2_hal.o dim2_sysfs.o
-CFLAGS_dim2_hdm.o := -I$(src)/../include/
-
-all:
- $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules
-
-modules_install:
- $(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
-
-clean:
- $(MAKE) -C $(KERNEL_SRC) M=$(SRC) clean
-
diff --git a/driver/hdm-dim2/dim2_hal.c b/driver/hdm-dim2/dim2_hal.c
index 0b9816c..28eaa2a 100644
--- a/driver/hdm-dim2/dim2_hal.c
+++ b/driver/hdm-dim2/dim2_hal.c
@@ -18,6 +18,7 @@
#include "dim2_errors.h"
#include "dim2_reg.h"
#include <linux/stddef.h>
+#include <linux/kernel.h>
/*
* Size factor for isochronous DBR buffer.
@@ -49,7 +50,7 @@
#define DBR_SIZE (16 * 1024) /* specified by IP */
#define DBR_BLOCK_SIZE (DBR_SIZE / 32 / DBR_MAP_SIZE)
-#define ROUND_UP_TO(x, d) (((x) + (d) - 1) / (d) * (d))
+#define ROUND_UP_TO(x, d) (DIV_ROUND_UP(x, (d)) * (d))
/* -------------------------------------------------------------------------- */
/* generic helper functions and macros */
@@ -117,7 +118,7 @@ static int alloc_dbr(u16 size)
return DBR_SIZE; /* out of memory */
for (i = 0; i < DBR_MAP_SIZE; i++) {
- u32 const blocks = (size + DBR_BLOCK_SIZE - 1) / DBR_BLOCK_SIZE;
+ u32 const blocks = DIV_ROUND_UP(size, DBR_BLOCK_SIZE);
u32 mask = ~((~(u32)0) << blocks);
do {
@@ -137,7 +138,7 @@ static int alloc_dbr(u16 size)
static void free_dbr(int offs, int size)
{
int block_idx = offs / DBR_BLOCK_SIZE;
- u32 const blocks = (size + DBR_BLOCK_SIZE - 1) / DBR_BLOCK_SIZE;
+ u32 const blocks = DIV_ROUND_UP(size, DBR_BLOCK_SIZE);
u32 mask = ~((~(u32)0) << blocks);
mask <<= block_idx % 32;
@@ -216,12 +217,15 @@ static inline void dim2_clear_ctr(u32 ctr_addr)
}
static void dim2_configure_cat(u8 cat_base, u8 ch_addr, u8 ch_type,
- bool read_not_write, bool sync_mfe)
+ bool read_not_write)
{
+ bool isoc_fce = ch_type == CAT_CT_VAL_ISOC;
+ bool sync_mfe = ch_type == CAT_CT_VAL_SYNC;
u16 const cat =
(read_not_write << CAT_RNW_BIT) |
(ch_type << CAT_CT_SHIFT) |
(ch_addr << CAT_CL_SHIFT) |
+ (isoc_fce << CAT_FCE_BIT) |
(sync_mfe << CAT_MFE_BIT) |
(false << CAT_MT_BIT) |
(true << CAT_CE_BIT);
@@ -349,13 +353,13 @@ static void dim2_clear_ctram(void)
static void dim2_configure_channel(
u8 ch_addr, u8 type, u8 is_tx, u16 dbr_address, u16 hw_buffer_size,
- u16 packet_length, bool sync_mfe)
+ u16 packet_length)
{
dim2_configure_cdt(ch_addr, dbr_address, hw_buffer_size, packet_length);
- dim2_configure_cat(MLB_CAT, ch_addr, type, is_tx ? 1 : 0, sync_mfe);
+ dim2_configure_cat(MLB_CAT, ch_addr, type, is_tx ? 1 : 0);
dim2_configure_adt(ch_addr);
- dim2_configure_cat(AHB_CAT, ch_addr, type, is_tx ? 0 : 1, sync_mfe);
+ dim2_configure_cat(AHB_CAT, ch_addr, type, is_tx ? 0 : 1);
/* unmask interrupt for used channel, enable mlb_sys_int[0] interrupt */
dimcb_io_write(&g.dim2->ACMR0,
@@ -762,7 +766,8 @@ static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx,
if (!check_channel_address(ch_address))
return DIM_INIT_ERR_CHANNEL_ADDRESS;
- ch->dbr_size = ROUND_UP_TO(hw_buffer_size, DBR_BLOCK_SIZE);
+ if (!ch->dbr_size)
+ ch->dbr_size = ROUND_UP_TO(hw_buffer_size, DBR_BLOCK_SIZE);
ch->dbr_addr = alloc_dbr(ch->dbr_size);
if (ch->dbr_addr >= DBR_SIZE)
return DIM_INIT_ERR_OUT_OF_MEMORY;
@@ -770,7 +775,7 @@ static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx,
channel_init(ch, ch_address / 2);
dim2_configure_channel(ch->addr, type, is_tx,
- ch->dbr_addr, ch->dbr_size, 0, false);
+ ch->dbr_addr, ch->dbr_size, 0);
return DIM_NO_ERROR;
}
@@ -848,7 +853,8 @@ u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
if (!check_packet_length(packet_length))
return DIM_ERR_BAD_CONFIG;
- ch->dbr_size = packet_length * ISOC_DBR_FACTOR;
+ if (!ch->dbr_size)
+ ch->dbr_size = packet_length * ISOC_DBR_FACTOR;
ch->dbr_addr = alloc_dbr(ch->dbr_size);
if (ch->dbr_addr >= DBR_SIZE)
return DIM_INIT_ERR_OUT_OF_MEMORY;
@@ -856,7 +862,7 @@ u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
isoc_init(ch, ch_address / 2, packet_length);
dim2_configure_channel(ch->addr, CAT_CT_VAL_ISOC, is_tx, ch->dbr_addr,
- ch->dbr_size, packet_length, false);
+ ch->dbr_size, packet_length);
return DIM_NO_ERROR;
}
@@ -875,7 +881,8 @@ u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
if (!check_bytes_per_frame(bytes_per_frame))
return DIM_ERR_BAD_CONFIG;
- ch->dbr_size = bytes_per_frame << bd_factor;
+ if (!ch->dbr_size)
+ ch->dbr_size = bytes_per_frame << bd_factor;
ch->dbr_addr = alloc_dbr(ch->dbr_size);
if (ch->dbr_addr >= DBR_SIZE)
return DIM_INIT_ERR_OUT_OF_MEMORY;
@@ -884,7 +891,7 @@ u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
dim2_clear_dbr(ch->dbr_addr, ch->dbr_size);
dim2_configure_channel(ch->addr, CAT_CT_VAL_SYNC, is_tx,
- ch->dbr_addr, ch->dbr_size, 0, true);
+ ch->dbr_addr, ch->dbr_size, 0);
return DIM_NO_ERROR;
}
diff --git a/driver/hdm-dim2/dim2_hdm.c b/driver/hdm-dim2/dim2_hdm.c
index 35aee9f..893b8e4 100644
--- a/driver/hdm-dim2/dim2_hdm.c
+++ b/driver/hdm-dim2/dim2_hdm.c
@@ -1,7 +1,7 @@
/*
* dim2_hdm.c - MediaLB DIM2 Hardware Dependent Module
*
- * Copyright (C) 2015-2016, Microchip Technology Germany II GmbH & Co. KG
+ * Copyright (C) 2015-2017, Microchip Technology Germany II GmbH & Co. KG
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -26,7 +26,6 @@
#include <linux/kthread.h>
#include <mostcore.h>
-#include <networking.h>
#include "dim2_hal.h"
#include "dim2_hdm.h"
#include "dim2_errors.h"
@@ -39,11 +38,6 @@
#define MAX_BUF_SIZE_PACKET 2048
#define MAX_BUF_SIZE_STREAMING (8 * 1024)
-/* command line parameter to select clock speed */
-static char *clock_speed;
-module_param(clock_speed, charp, 0);
-MODULE_PARM_DESC(clock_speed, "MediaLB Clock Speed");
-
/*
* The parameter representing the number of frames per sub-buffer for
* synchronous channels. Valid values: [0 .. 6].
@@ -52,7 +46,7 @@ MODULE_PARM_DESC(clock_speed, "MediaLB Clock Speed");
* sub-buffer 1, 2, 4, 8, 16, 32, 64.
*/
static u8 fcnt = 4; /* (1 << fcnt) frames per subbuffer */
-module_param(fcnt, byte, 0);
+module_param(fcnt, byte, 0000);
MODULE_PARM_DESC(fcnt, "Num of frames per sub-buffer for sync channels as a power of 2");
static DEFINE_SPINLOCK(dim_lock);
@@ -73,6 +67,7 @@ struct hdm_channel {
char name[sizeof "caNNN"];
bool is_initialized;
struct dim_channel ch;
+ u16 *reset_dbr_size;
struct list_head pending_list; /* before dim_enqueue_buffer() */
struct list_head started_list; /* after dim_enqueue_buffer() */
enum most_channel_direction direction;
@@ -85,7 +80,6 @@ struct hdm_channel {
* @most_iface: most interface structure
* @capabilities: an array of channel capability data
* @io_base: I/O register base address
- * @clk_speed: user selectable (through command line parameter) clock speed
* @netinfo_task: thread to deliver network status
* @netinfo_waitq: waitq for the thread to sleep
* @deliver_netinfo: to identify whether network status received
@@ -99,7 +93,6 @@ struct dim2_hdm {
struct most_interface most_iface;
char name[16 + sizeof "dim2-"];
void __iomem *io_base;
- int clk_speed;
struct task_struct *netinfo_task;
wait_queue_head_t netinfo_waitq;
int deliver_netinfo;
@@ -107,6 +100,8 @@ struct dim2_hdm {
unsigned char link_state;
int atx_idx;
struct medialb_bus bus;
+ void (*on_netinfo)(struct most_interface *,
+ unsigned char, unsigned char *);
};
#define iface_to_hdm(iface) container_of(iface, struct dim2_hdm, most_iface)
@@ -162,52 +157,25 @@ void dimcb_on_error(u8 error_id, const char *error_message)
/**
* startup_dim - initialize the dim2 interface
* @pdev: platform device
- *
- * Get the value of command line parameter "clock_speed" if given or use the
- * default value, enable the clock and PLL, and initialize the dim2 interface.
*/
static int startup_dim(struct platform_device *pdev)
{
struct dim2_hdm *dev = platform_get_drvdata(pdev);
struct dim2_platform_data *pdata = pdev->dev.platform_data;
u8 hal_ret;
+ int ret;
- dev->clk_speed = -1;
-
- if (clock_speed) {
- if (!strcmp(clock_speed, "256fs"))
- dev->clk_speed = CLK_256FS;
- else if (!strcmp(clock_speed, "512fs"))
- dev->clk_speed = CLK_512FS;
- else if (!strcmp(clock_speed, "1024fs"))
- dev->clk_speed = CLK_1024FS;
- else if (!strcmp(clock_speed, "2048fs"))
- dev->clk_speed = CLK_2048FS;
- else if (!strcmp(clock_speed, "3072fs"))
- dev->clk_speed = CLK_3072FS;
- else if (!strcmp(clock_speed, "4096fs"))
- dev->clk_speed = CLK_4096FS;
- else if (!strcmp(clock_speed, "6144fs"))
- dev->clk_speed = CLK_6144FS;
- else if (!strcmp(clock_speed, "8192fs"))
- dev->clk_speed = CLK_8192FS;
- }
-
- if (dev->clk_speed == -1) {
- pr_info("Bad or missing clock speed parameter, using default value: 3072fs\n");
- dev->clk_speed = CLK_3072FS;
- } else {
- pr_info("Selected clock speed: %s\n", clock_speed);
+ if (!pdata) {
+ pr_err("missing platform data\n");
+ return -EINVAL;
}
- if (pdata && pdata->init) {
- int ret = pdata->init(pdata, dev->io_base, dev->clk_speed);
- if (ret)
- return ret;
- }
+ ret = pdata->init ? pdata->init(pdata, dev->io_base) : 0;
+ if (ret)
+ return ret;
pr_info("sync: num of frames per sub-buffer: %u\n", fcnt);
- hal_ret = dim_startup(dev->io_base, dev->clk_speed, fcnt);
+ hal_ret = dim_startup(dev->io_base, pdata->clk_speed, fcnt);
if (hal_ret != DIM_NO_ERROR) {
pr_err("dim_startup failed: %d\n", hal_ret);
if (pdata && pdata->destroy)
@@ -287,8 +255,11 @@ static int deliver_netinfo_thread(void *data)
if (dev->deliver_netinfo) {
dev->deliver_netinfo--;
- most_deliver_netinfo(&dev->most_iface, dev->link_state,
- dev->mac_addrs);
+ if (dev->on_netinfo) {
+ dev->on_netinfo(&dev->most_iface,
+ dev->link_state,
+ dev->mac_addrs);
+ }
}
}
@@ -529,6 +500,12 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx,
if (hdm_ch->is_initialized)
return -EPERM;
+ /* do not reset if the property was set by user, see poison_channel */
+ hdm_ch->reset_dbr_size = ccfg->dbr_size ? NULL : &ccfg->dbr_size;
+
+ /* zero value is default dbr_size, see dim2 hal */
+ hdm_ch->ch.dbr_size = ccfg->dbr_size;
+
switch (ccfg->data_type) {
case MOST_CH_CONTROL:
new_size = dim_norm_ctrl_async_buffer_size(buf_size);
@@ -609,6 +586,7 @@ static int configure_channel(struct most_interface *most_iface, int ch_idx,
dev->atx_idx = ch_idx;
spin_unlock_irqrestore(&dim_lock, flags);
+ ccfg->dbr_size = hdm_ch->ch.dbr_size;
return 0;
}
@@ -654,12 +632,18 @@ static int enqueue(struct most_interface *most_iface, int ch_idx,
* Send a command to INIC which triggers retrieving of network info by means of
* "Message exchange over MDP/MEP". Return 0 on success, negative on failure.
*/
-static void request_netinfo(struct most_interface *most_iface, int ch_idx)
+static void request_netinfo(struct most_interface *most_iface, int ch_idx,
+ void (*on_netinfo)(struct most_interface *,
+ unsigned char, unsigned char *))
{
struct dim2_hdm *dev = iface_to_hdm(most_iface);
struct mbo *mbo;
u8 *data;
+ dev->on_netinfo = on_netinfo;
+ if (!on_netinfo)
+ return;
+
if (dev->atx_idx < 0) {
pr_err("Async Tx Not initialized\n");
return;
@@ -718,10 +702,22 @@ static int poison_channel(struct most_interface *most_iface, int ch_idx)
complete_all_mbos(&hdm_ch->started_list);
complete_all_mbos(&hdm_ch->pending_list);
+ if (hdm_ch->reset_dbr_size)
+ *hdm_ch->reset_dbr_size = 0;
return ret;
}
+static void *dma_alloc(struct mbo *mbo, u32 size)
+{
+ return dma_alloc_coherent(NULL, size, &mbo->bus_address, GFP_KERNEL);
+}
+
+static void dma_free(struct mbo *mbo, u32 size)
+{
+ dma_free_coherent(NULL, size, mbo->virt_address, mbo->bus_address);
+}
+
/*
* dim2_probe - dim2 probe handler
* @pdev: platform device structure
@@ -751,8 +747,8 @@ static int dim2_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- dev_err(&pdev->dev, "failed to get ahb0_int irq\n");
- return -ENODEV;
+ dev_err(&pdev->dev, "failed to get ahb0_int irq: %d\n", irq);
+ return irq;
}
ret = devm_request_irq(&pdev->dev, irq, dim2_ahb_isr, 0,
@@ -764,8 +760,8 @@ static int dim2_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 1);
if (irq < 0) {
- dev_err(&pdev->dev, "failed to get mlb_int irq\n");
- return -ENODEV;
+ dev_err(&pdev->dev, "failed to get mlb_int irq: %d\n", irq);
+ return irq;
}
ret = devm_request_irq(&pdev->dev, irq, dim2_mlb_isr, 0,
@@ -820,8 +816,11 @@ static int dim2_probe(struct platform_device *pdev)
dev->most_iface.channel_vector = dev->capabilities;
dev->most_iface.configure = configure_channel;
dev->most_iface.enqueue = enqueue;
+ dev->most_iface.dma_alloc = dma_alloc;
+ dev->most_iface.dma_free = dma_free;
dev->most_iface.poison_channel = poison_channel;
dev->most_iface.request_netinfo = request_netinfo;
+ dev->most_iface.extra_attrs = DBR_ATTRS;
kobj = most_register_interface(&dev->most_iface);
if (IS_ERR(kobj)) {
@@ -884,7 +883,7 @@ static int dim2_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_device_id dim2_id[] = {
+static const struct platform_device_id dim2_id[] = {
{ "medialb_dim2" },
{ }, /* Terminating entry */
};
diff --git a/driver/hdm-dim2/dim2_hdm.h b/driver/hdm-dim2/dim2_hdm.h
index 4050e7c..e2a780f 100644
--- a/driver/hdm-dim2/dim2_hdm.h
+++ b/driver/hdm-dim2/dim2_hdm.h
@@ -1,7 +1,7 @@
/*
* dim2_hdm.h - MediaLB DIM2 HDM Header
*
- * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
+ * Copyright (C) 2015-2017, Microchip Technology Germany II GmbH & Co. KG
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -14,14 +14,15 @@
#ifndef DIM2_HDM_H
#define DIM2_HDM_H
+#include <linux/types.h>
+
struct device;
/* platform dependent data for dim2 interface */
struct dim2_platform_data {
- int (*init)(struct dim2_platform_data *pd, void __iomem *io_base,
- int clk_speed);
+ int (*init)(struct dim2_platform_data *pd, void __iomem *io_base);
void (*destroy)(struct dim2_platform_data *pd);
- void *priv;
+ u8 clk_speed;
};
#endif /* DIM2_HDM_H */
diff --git a/driver/hdm-dim2/dim2_reg.h b/driver/hdm-dim2/dim2_reg.h
index 01fe499..f7d9fbc 100644
--- a/driver/hdm-dim2/dim2_reg.h
+++ b/driver/hdm-dim2/dim2_reg.h
@@ -141,6 +141,7 @@ enum {
ADT1_CTRL_ASYNC_BD_MASK = DIM2_MASK(11),
ADT1_ISOC_SYNC_BD_MASK = DIM2_MASK(13),
+ CAT_FCE_BIT = 14,
CAT_MFE_BIT = 14,
CAT_MT_BIT = 13,