mirror of https://github.com/torvalds/linux.git
net: macb: Add TAPRIO traffic scheduling support
Implement Time-Aware Traffic Scheduling (TAPRIO) offload support
for Cadence MACB/GEM ethernet controllers to enable IEEE 802.1Qbv
compliant time-sensitive networking (TSN) capabilities.
Key Features:
1. Enhanced Scheduled Traffic (ENST) Register Management
- Per-queue ENST registers: ENST_START_TIME, ENST_ON_TIME, ENST_OFF_TIME
- Centralized control via ENST_CONTROL for gate enable/disable
- Infrastructure enhancements:
* Extended macb_queue structure with ENST timing control registers
* Mapped ENST register offsets into queue management framework
* Introduced macb_queue_enst_config for per-entry TC configuration
- Timing conversion utility:
* enst_ns_to_hw_units(): Converts nanoseconds to hardware units
* Timing values are programmed as hardware units based on link speed
* Conversion formula: time_bytes = time_ns / divisor
* Speed-specific divisors: 1Gbps=8, 100Mbps=80, 10Mbps=800
- Hardware limit utility:
* enst_max_hw_interval(): Returns max interval for given speed
2. TAPRIO Configuration via "tc qdisc replace"
- macb_taprio_setup_replace(): Configures TAPRIO hardware offload
- Parameter validation checks performed:
* TC entry limit validation against available hardware queues
* Base time non-negativity enforcement
* Speed-adaptive timing constraint verification
* Cycle time vs. total gate time consistency checks
* Single-queue gate mask enforcement per scheduling entry
- Programming sequence:
* GEM doesn't support changing ENST registers if ENST is enabled,
hence disable ENST before programming
* Atomic timing register configuration (START_TIME, ON_TIME, OFF_TIME)
* Enable queues via ENST_CONTROL
3. TAPRIO Cleanup via "tc qdisc destroy"
- macb_taprio_destroy(): Safely removes TAPRIO configuration
- Restores default queue behavior
- Cleanup steps:
* Reset TC state
* Disable ENST
* Clear timing registers
* Ensure atomic updates with locking
4. Traffic Control Offload Infrastructure
- macb_setup_taprio(): TAPRIO command dispatcher
* Verifies hardware support
* Handles runtime suspend state
- macb_setup_tc(): TC_SETUP_QDISC_TAPRIO entry point
- Supports REPLACE and DESTROY operations
Tested on Xilinx Versal platforms with QBV-capable MACB controllers.
Signed-off-by: Vineeth Karumanchi <vineeth.karumanchi@amd.com>
Link: https://patch.msgid.link/20250814071058.3062453-2-vineeth.karumanchi@amd.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
6089970b07
commit
89934dbf16
|
|
@ -184,6 +184,13 @@
|
||||||
#define GEM_DCFG8 0x029C /* Design Config 8 */
|
#define GEM_DCFG8 0x029C /* Design Config 8 */
|
||||||
#define GEM_DCFG10 0x02A4 /* Design Config 10 */
|
#define GEM_DCFG10 0x02A4 /* Design Config 10 */
|
||||||
#define GEM_DCFG12 0x02AC /* Design Config 12 */
|
#define GEM_DCFG12 0x02AC /* Design Config 12 */
|
||||||
|
#define GEM_ENST_START_TIME_Q0 0x0800 /* ENST Q0 start time */
|
||||||
|
#define GEM_ENST_START_TIME_Q1 0x0804 /* ENST Q1 start time */
|
||||||
|
#define GEM_ENST_ON_TIME_Q0 0x0820 /* ENST Q0 on time */
|
||||||
|
#define GEM_ENST_ON_TIME_Q1 0x0824 /* ENST Q1 on time */
|
||||||
|
#define GEM_ENST_OFF_TIME_Q0 0x0840 /* ENST Q0 off time */
|
||||||
|
#define GEM_ENST_OFF_TIME_Q1 0x0844 /* ENST Q1 off time */
|
||||||
|
#define GEM_ENST_CONTROL 0x0880 /* ENST control register */
|
||||||
#define GEM_USX_CONTROL 0x0A80 /* High speed PCS control register */
|
#define GEM_USX_CONTROL 0x0A80 /* High speed PCS control register */
|
||||||
#define GEM_USX_STATUS 0x0A88 /* High speed PCS status register */
|
#define GEM_USX_STATUS 0x0A88 /* High speed PCS status register */
|
||||||
|
|
||||||
|
|
@ -221,6 +228,13 @@
|
||||||
#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2))
|
#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2))
|
||||||
#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2))
|
#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2))
|
||||||
|
|
||||||
|
#define GEM_ENST_START_TIME(hw_q) (0x0800 + ((hw_q) << 2))
|
||||||
|
#define GEM_ENST_ON_TIME(hw_q) (0x0820 + ((hw_q) << 2))
|
||||||
|
#define GEM_ENST_OFF_TIME(hw_q) (0x0840 + ((hw_q) << 2))
|
||||||
|
|
||||||
|
/* Bitfields in ENST_CONTROL */
|
||||||
|
#define GEM_ENST_DISABLE_QUEUE_OFFSET 16
|
||||||
|
|
||||||
/* Bitfields in NCR */
|
/* Bitfields in NCR */
|
||||||
#define MACB_LB_OFFSET 0 /* reserved */
|
#define MACB_LB_OFFSET 0 /* reserved */
|
||||||
#define MACB_LB_SIZE 1
|
#define MACB_LB_SIZE 1
|
||||||
|
|
@ -554,6 +568,23 @@
|
||||||
#define GEM_HIGH_SPEED_OFFSET 26
|
#define GEM_HIGH_SPEED_OFFSET 26
|
||||||
#define GEM_HIGH_SPEED_SIZE 1
|
#define GEM_HIGH_SPEED_SIZE 1
|
||||||
|
|
||||||
|
/* Bitfields in ENST_START_TIME_Qx. */
|
||||||
|
#define GEM_START_TIME_SEC_OFFSET 30
|
||||||
|
#define GEM_START_TIME_SEC_SIZE 2
|
||||||
|
#define GEM_START_TIME_NSEC_OFFSET 0
|
||||||
|
#define GEM_START_TIME_NSEC_SIZE 30
|
||||||
|
|
||||||
|
/* Bitfields in ENST_ON_TIME_Qx. */
|
||||||
|
#define GEM_ON_TIME_OFFSET 0
|
||||||
|
#define GEM_ON_TIME_SIZE 17
|
||||||
|
|
||||||
|
/* Bitfields in ENST_OFF_TIME_Qx. */
|
||||||
|
#define GEM_OFF_TIME_OFFSET 0
|
||||||
|
#define GEM_OFF_TIME_SIZE 17
|
||||||
|
|
||||||
|
/* Hardware ENST timing registers granularity */
|
||||||
|
#define ENST_TIME_GRANULARITY_NS 8
|
||||||
|
|
||||||
/* Bitfields in USX_CONTROL. */
|
/* Bitfields in USX_CONTROL. */
|
||||||
#define GEM_USX_CTRL_SPEED_OFFSET 14
|
#define GEM_USX_CTRL_SPEED_OFFSET 14
|
||||||
#define GEM_USX_CTRL_SPEED_SIZE 3
|
#define GEM_USX_CTRL_SPEED_SIZE 3
|
||||||
|
|
@ -1219,6 +1250,11 @@ struct macb_queue {
|
||||||
unsigned int RBQP;
|
unsigned int RBQP;
|
||||||
unsigned int RBQPH;
|
unsigned int RBQPH;
|
||||||
|
|
||||||
|
/* ENST register offsets for this queue */
|
||||||
|
unsigned int ENST_START_TIME;
|
||||||
|
unsigned int ENST_ON_TIME;
|
||||||
|
unsigned int ENST_OFF_TIME;
|
||||||
|
|
||||||
/* Lock to protect tx_head and tx_tail */
|
/* Lock to protect tx_head and tx_tail */
|
||||||
spinlock_t tx_ptr_lock;
|
spinlock_t tx_ptr_lock;
|
||||||
unsigned int tx_head, tx_tail;
|
unsigned int tx_head, tx_tail;
|
||||||
|
|
@ -1397,6 +1433,19 @@ static inline bool gem_has_ptp(struct macb *bp)
|
||||||
return IS_ENABLED(CONFIG_MACB_USE_HWSTAMP) && (bp->caps & MACB_CAPS_GEM_HAS_PTP);
|
return IS_ENABLED(CONFIG_MACB_USE_HWSTAMP) && (bp->caps & MACB_CAPS_GEM_HAS_PTP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ENST Helper functions */
|
||||||
|
static inline u64 enst_ns_to_hw_units(size_t ns, u32 speed_mbps)
|
||||||
|
{
|
||||||
|
return DIV_ROUND_UP((ns) * (speed_mbps),
|
||||||
|
(ENST_TIME_GRANULARITY_NS * 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u64 enst_max_hw_interval(u32 speed_mbps)
|
||||||
|
{
|
||||||
|
return DIV_ROUND_UP(GENMASK(GEM_ON_TIME_SIZE - 1, 0) *
|
||||||
|
ENST_TIME_GRANULARITY_NS * 1000, (speed_mbps));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct macb_platform_data - platform data for MACB Ethernet used for PCI registration
|
* struct macb_platform_data - platform data for MACB Ethernet used for PCI registration
|
||||||
* @pclk: platform clock
|
* @pclk: platform clock
|
||||||
|
|
@ -1407,4 +1456,21 @@ struct macb_platform_data {
|
||||||
struct clk *hclk;
|
struct clk *hclk;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct macb_queue_enst_config - Configuration for Enhanced Scheduled Traffic
|
||||||
|
* @start_time_mask: Bitmask representing the start time for the queue
|
||||||
|
* @on_time_bytes: "on" time nsec expressed in bytes
|
||||||
|
* @off_time_bytes: "off" time nsec expressed in bytes
|
||||||
|
* @queue_id: Identifier for the queue
|
||||||
|
*
|
||||||
|
* This structure holds the configuration parameters for an ENST queue,
|
||||||
|
* used to control time-based transmission scheduling in the MACB driver.
|
||||||
|
*/
|
||||||
|
struct macb_queue_enst_config {
|
||||||
|
u32 start_time_mask;
|
||||||
|
u32 on_time_bytes;
|
||||||
|
u32 off_time_bytes;
|
||||||
|
u8 queue_id;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _MACB_H */
|
#endif /* _MACB_H */
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
#include <linux/reset.h>
|
#include <linux/reset.h>
|
||||||
#include <linux/firmware/xlnx-zynqmp.h>
|
#include <linux/firmware/xlnx-zynqmp.h>
|
||||||
#include <linux/inetdevice.h>
|
#include <linux/inetdevice.h>
|
||||||
|
#include <net/pkt_sched.h>
|
||||||
#include "macb.h"
|
#include "macb.h"
|
||||||
|
|
||||||
/* This structure is only used for MACB on SiFive FU540 devices */
|
/* This structure is only used for MACB on SiFive FU540 devices */
|
||||||
|
|
@ -4084,6 +4085,223 @@ static void macb_restore_features(struct macb *bp)
|
||||||
macb_set_rxflow_feature(bp, features);
|
macb_set_rxflow_feature(bp, features);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int macb_taprio_setup_replace(struct net_device *ndev,
|
||||||
|
struct tc_taprio_qopt_offload *conf)
|
||||||
|
{
|
||||||
|
u64 total_on_time = 0, start_time_sec = 0, start_time = conf->base_time;
|
||||||
|
u32 configured_queues = 0, speed = 0, start_time_nsec;
|
||||||
|
struct macb_queue_enst_config *enst_queue;
|
||||||
|
struct tc_taprio_sched_entry *entry;
|
||||||
|
struct macb *bp = netdev_priv(ndev);
|
||||||
|
struct ethtool_link_ksettings kset;
|
||||||
|
struct macb_queue *queue;
|
||||||
|
size_t i;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (conf->num_entries > bp->num_queues) {
|
||||||
|
netdev_err(ndev, "Too many TAPRIO entries: %zu > %d queues\n",
|
||||||
|
conf->num_entries, bp->num_queues);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_time < 0) {
|
||||||
|
netdev_err(ndev, "Invalid base_time: must be 0 or positive, got %lld\n",
|
||||||
|
conf->base_time);
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the current link speed */
|
||||||
|
err = phylink_ethtool_ksettings_get(bp->phylink, &kset);
|
||||||
|
if (unlikely(err)) {
|
||||||
|
netdev_err(ndev, "Failed to get link settings: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
speed = kset.base.speed;
|
||||||
|
if (unlikely(speed <= 0)) {
|
||||||
|
netdev_err(ndev, "Invalid speed: %d\n", speed);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
enst_queue = kcalloc(conf->num_entries, sizeof(*enst_queue), GFP_KERNEL);
|
||||||
|
if (unlikely(!enst_queue))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* Pre-validate all entries before making any hardware changes */
|
||||||
|
for (i = 0; i < conf->num_entries; i++) {
|
||||||
|
entry = &conf->entries[i];
|
||||||
|
|
||||||
|
if (entry->command != TC_TAPRIO_CMD_SET_GATES) {
|
||||||
|
netdev_err(ndev, "Entry %zu: unsupported command %d\n",
|
||||||
|
i, entry->command);
|
||||||
|
err = -EOPNOTSUPP;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate gate_mask: must be nonzero, single queue, and within range */
|
||||||
|
if (!is_power_of_2(entry->gate_mask)) {
|
||||||
|
netdev_err(ndev, "Entry %zu: gate_mask 0x%x is not a power of 2 (only one queue per entry allowed)\n",
|
||||||
|
i, entry->gate_mask);
|
||||||
|
err = -EINVAL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* gate_mask must not select queues outside the valid queue_mask */
|
||||||
|
if (entry->gate_mask & ~bp->queue_mask) {
|
||||||
|
netdev_err(ndev, "Entry %zu: gate_mask 0x%x exceeds queue range (max_queues=%d)\n",
|
||||||
|
i, entry->gate_mask, bp->num_queues);
|
||||||
|
err = -EINVAL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for start time limits */
|
||||||
|
start_time_sec = start_time;
|
||||||
|
start_time_nsec = do_div(start_time_sec, NSEC_PER_SEC);
|
||||||
|
if (start_time_sec > GENMASK(GEM_START_TIME_SEC_SIZE - 1, 0)) {
|
||||||
|
netdev_err(ndev, "Entry %zu: Start time %llu s exceeds hardware limit\n",
|
||||||
|
i, start_time_sec);
|
||||||
|
err = -ERANGE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for on time limit */
|
||||||
|
if (entry->interval > enst_max_hw_interval(speed)) {
|
||||||
|
netdev_err(ndev, "Entry %zu: interval %u ns exceeds hardware limit %llu ns\n",
|
||||||
|
i, entry->interval, enst_max_hw_interval(speed));
|
||||||
|
err = -ERANGE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for off time limit*/
|
||||||
|
if ((conf->cycle_time - entry->interval) > enst_max_hw_interval(speed)) {
|
||||||
|
netdev_err(ndev, "Entry %zu: off_time %llu ns exceeds hardware limit %llu ns\n",
|
||||||
|
i, conf->cycle_time - entry->interval,
|
||||||
|
enst_max_hw_interval(speed));
|
||||||
|
err = -ERANGE;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
enst_queue[i].queue_id = order_base_2(entry->gate_mask);
|
||||||
|
enst_queue[i].start_time_mask =
|
||||||
|
(start_time_sec << GEM_START_TIME_SEC_OFFSET) |
|
||||||
|
start_time_nsec;
|
||||||
|
enst_queue[i].on_time_bytes =
|
||||||
|
enst_ns_to_hw_units(entry->interval, speed);
|
||||||
|
enst_queue[i].off_time_bytes =
|
||||||
|
enst_ns_to_hw_units(conf->cycle_time - entry->interval, speed);
|
||||||
|
|
||||||
|
configured_queues |= entry->gate_mask;
|
||||||
|
total_on_time += entry->interval;
|
||||||
|
start_time += entry->interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check total interval doesn't exceed cycle time */
|
||||||
|
if (total_on_time > conf->cycle_time) {
|
||||||
|
netdev_err(ndev, "Total ON %llu ns exceeds cycle time %llu ns\n",
|
||||||
|
total_on_time, conf->cycle_time);
|
||||||
|
err = -EINVAL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
netdev_dbg(ndev, "TAPRIO setup: %zu entries, base_time=%lld ns, cycle_time=%llu ns\n",
|
||||||
|
conf->num_entries, conf->base_time, conf->cycle_time);
|
||||||
|
|
||||||
|
/* All validations passed - proceed with hardware configuration */
|
||||||
|
scoped_guard(spinlock_irqsave, &bp->lock) {
|
||||||
|
/* Disable ENST queues if running before configuring */
|
||||||
|
gem_writel(bp, ENST_CONTROL,
|
||||||
|
bp->queue_mask << GEM_ENST_DISABLE_QUEUE_OFFSET);
|
||||||
|
|
||||||
|
for (i = 0; i < conf->num_entries; i++) {
|
||||||
|
queue = &bp->queues[enst_queue[i].queue_id];
|
||||||
|
/* Configure queue timing registers */
|
||||||
|
queue_writel(queue, ENST_START_TIME,
|
||||||
|
enst_queue[i].start_time_mask);
|
||||||
|
queue_writel(queue, ENST_ON_TIME,
|
||||||
|
enst_queue[i].on_time_bytes);
|
||||||
|
queue_writel(queue, ENST_OFF_TIME,
|
||||||
|
enst_queue[i].off_time_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable ENST for all configured queues in one write */
|
||||||
|
gem_writel(bp, ENST_CONTROL, configured_queues);
|
||||||
|
}
|
||||||
|
|
||||||
|
netdev_info(ndev, "TAPRIO configuration completed successfully: %zu entries, %d queues configured\n",
|
||||||
|
conf->num_entries, hweight32(configured_queues));
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
kfree(enst_queue);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void macb_taprio_destroy(struct net_device *ndev)
|
||||||
|
{
|
||||||
|
struct macb *bp = netdev_priv(ndev);
|
||||||
|
struct macb_queue *queue;
|
||||||
|
u32 enst_disable_mask;
|
||||||
|
unsigned int q;
|
||||||
|
|
||||||
|
netdev_reset_tc(ndev);
|
||||||
|
enst_disable_mask = bp->queue_mask << GEM_ENST_DISABLE_QUEUE_OFFSET;
|
||||||
|
|
||||||
|
scoped_guard(spinlock_irqsave, &bp->lock) {
|
||||||
|
/* Single disable command for all queues */
|
||||||
|
gem_writel(bp, ENST_CONTROL, enst_disable_mask);
|
||||||
|
|
||||||
|
/* Clear all queue ENST registers in batch */
|
||||||
|
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
|
||||||
|
queue_writel(queue, ENST_START_TIME, 0);
|
||||||
|
queue_writel(queue, ENST_ON_TIME, 0);
|
||||||
|
queue_writel(queue, ENST_OFF_TIME, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
netdev_info(ndev, "TAPRIO destroy: All gates disabled\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int macb_setup_taprio(struct net_device *ndev,
|
||||||
|
struct tc_taprio_qopt_offload *taprio)
|
||||||
|
{
|
||||||
|
struct macb *bp = netdev_priv(ndev);
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (unlikely(!(ndev->hw_features & NETIF_F_HW_TC)))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
/* Check if Device is in runtime suspend */
|
||||||
|
if (unlikely(pm_runtime_suspended(&bp->pdev->dev))) {
|
||||||
|
netdev_err(ndev, "Device is in runtime suspend\n");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (taprio->cmd) {
|
||||||
|
case TAPRIO_CMD_REPLACE:
|
||||||
|
err = macb_taprio_setup_replace(ndev, taprio);
|
||||||
|
break;
|
||||||
|
case TAPRIO_CMD_DESTROY:
|
||||||
|
macb_taprio_destroy(ndev);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
err = -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int macb_setup_tc(struct net_device *dev, enum tc_setup_type type,
|
||||||
|
void *type_data)
|
||||||
|
{
|
||||||
|
if (!dev || !type_data)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case TC_SETUP_QDISC_TAPRIO:
|
||||||
|
return macb_setup_taprio(dev, type_data);
|
||||||
|
default:
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const struct net_device_ops macb_netdev_ops = {
|
static const struct net_device_ops macb_netdev_ops = {
|
||||||
.ndo_open = macb_open,
|
.ndo_open = macb_open,
|
||||||
.ndo_stop = macb_close,
|
.ndo_stop = macb_close,
|
||||||
|
|
@ -4101,6 +4319,7 @@ static const struct net_device_ops macb_netdev_ops = {
|
||||||
.ndo_features_check = macb_features_check,
|
.ndo_features_check = macb_features_check,
|
||||||
.ndo_hwtstamp_set = macb_hwtstamp_set,
|
.ndo_hwtstamp_set = macb_hwtstamp_set,
|
||||||
.ndo_hwtstamp_get = macb_hwtstamp_get,
|
.ndo_hwtstamp_get = macb_hwtstamp_get,
|
||||||
|
.ndo_setup_tc = macb_setup_tc,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Configure peripheral capabilities according to device tree
|
/* Configure peripheral capabilities according to device tree
|
||||||
|
|
@ -4327,6 +4546,10 @@ static int macb_init(struct platform_device *pdev)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
queue->ENST_START_TIME = GEM_ENST_START_TIME(hw_q);
|
||||||
|
queue->ENST_ON_TIME = GEM_ENST_ON_TIME(hw_q);
|
||||||
|
queue->ENST_OFF_TIME = GEM_ENST_OFF_TIME(hw_q);
|
||||||
|
|
||||||
/* get irq: here we use the linux queue index, not the hardware
|
/* get irq: here we use the linux queue index, not the hardware
|
||||||
* queue index. the queue irq definitions in the device tree
|
* queue index. the queue irq definitions in the device tree
|
||||||
* must remove the optional gaps that could exist in the
|
* must remove the optional gaps that could exist in the
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue