diff options
Diffstat (limited to 'driver/hdm-dim2')
-rw-r--r-- | driver/hdm-dim2/Makefile | 18 | ||||
-rw-r--r-- | driver/hdm-dim2/dim2_hal.c | 33 | ||||
-rw-r--r-- | driver/hdm-dim2/dim2_hdm.c | 105 | ||||
-rw-r--r-- | driver/hdm-dim2/dim2_hdm.h | 9 | ||||
-rw-r--r-- | driver/hdm-dim2/dim2_reg.h | 1 |
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, |