|  | // SPDX-License-Identifier: GPL-2.0+ | 
|  |  | 
|  | #include "lan966x_main.h" | 
|  |  | 
|  | #define LAN966X_TAPRIO_TIMEOUT_MS		1000 | 
|  | #define LAN966X_TAPRIO_ENTRIES_PER_PORT		2 | 
|  |  | 
|  | /* Minimum supported cycle time in nanoseconds */ | 
|  | #define LAN966X_TAPRIO_MIN_CYCLE_TIME_NS	NSEC_PER_USEC | 
|  |  | 
|  | /* Maximum supported cycle time in nanoseconds */ | 
|  | #define LAN966X_TAPRIO_MAX_CYCLE_TIME_NS	(NSEC_PER_SEC - 1) | 
|  |  | 
|  | /* Total number of TAS GCL entries */ | 
|  | #define LAN966X_TAPRIO_NUM_GCL			256 | 
|  |  | 
|  | /* TAPRIO link speeds for calculation of guard band */ | 
|  | enum lan966x_taprio_link_speed { | 
|  | LAN966X_TAPRIO_SPEED_NO_GB, | 
|  | LAN966X_TAPRIO_SPEED_10, | 
|  | LAN966X_TAPRIO_SPEED_100, | 
|  | LAN966X_TAPRIO_SPEED_1000, | 
|  | LAN966X_TAPRIO_SPEED_2500, | 
|  | }; | 
|  |  | 
|  | /* TAPRIO list states */ | 
|  | enum lan966x_taprio_state { | 
|  | LAN966X_TAPRIO_STATE_ADMIN, | 
|  | LAN966X_TAPRIO_STATE_ADVANCING, | 
|  | LAN966X_TAPRIO_STATE_PENDING, | 
|  | LAN966X_TAPRIO_STATE_OPERATING, | 
|  | LAN966X_TAPRIO_STATE_TERMINATING, | 
|  | LAN966X_TAPRIO_STATE_MAX, | 
|  | }; | 
|  |  | 
|  | /* TAPRIO GCL command */ | 
|  | enum lan966x_taprio_gcl_cmd { | 
|  | LAN966X_TAPRIO_GCL_CMD_SET_GATE_STATES = 0, | 
|  | }; | 
|  |  | 
|  | static u32 lan966x_taprio_list_index(struct lan966x_port *port, u8 entry) | 
|  | { | 
|  | return port->chip_port * LAN966X_TAPRIO_ENTRIES_PER_PORT + entry; | 
|  | } | 
|  |  | 
|  | static u32 lan966x_taprio_list_state_get(struct lan966x_port *port) | 
|  | { | 
|  | struct lan966x *lan966x = port->lan966x; | 
|  | u32 val; | 
|  |  | 
|  | val = lan_rd(lan966x, QSYS_TAS_LST); | 
|  | return QSYS_TAS_LST_LIST_STATE_GET(val); | 
|  | } | 
|  |  | 
|  | static u32 lan966x_taprio_list_index_state_get(struct lan966x_port *port, | 
|  | u32 list) | 
|  | { | 
|  | struct lan966x *lan966x = port->lan966x; | 
|  |  | 
|  | lan_rmw(QSYS_TAS_CFG_CTRL_LIST_NUM_SET(list), | 
|  | QSYS_TAS_CFG_CTRL_LIST_NUM, | 
|  | lan966x, QSYS_TAS_CFG_CTRL); | 
|  |  | 
|  | return lan966x_taprio_list_state_get(port); | 
|  | } | 
|  |  | 
|  | static void lan966x_taprio_list_state_set(struct lan966x_port *port, | 
|  | u32 state) | 
|  | { | 
|  | struct lan966x *lan966x = port->lan966x; | 
|  |  | 
|  | lan_rmw(QSYS_TAS_LST_LIST_STATE_SET(state), | 
|  | QSYS_TAS_LST_LIST_STATE, | 
|  | lan966x, QSYS_TAS_LST); | 
|  | } | 
|  |  | 
|  | static int lan966x_taprio_list_shutdown(struct lan966x_port *port, | 
|  | u32 list) | 
|  | { | 
|  | struct lan966x *lan966x = port->lan966x; | 
|  | bool pending, operating; | 
|  | unsigned long end; | 
|  | u32 state; | 
|  |  | 
|  | end = jiffies +  msecs_to_jiffies(LAN966X_TAPRIO_TIMEOUT_MS); | 
|  | /* It is required to try multiple times to set the state of list, | 
|  | * because the HW can overwrite this. | 
|  | */ | 
|  | do { | 
|  | state = lan966x_taprio_list_state_get(port); | 
|  |  | 
|  | pending = false; | 
|  | operating = false; | 
|  |  | 
|  | if (state == LAN966X_TAPRIO_STATE_ADVANCING || | 
|  | state == LAN966X_TAPRIO_STATE_PENDING) { | 
|  | lan966x_taprio_list_state_set(port, | 
|  | LAN966X_TAPRIO_STATE_ADMIN); | 
|  | pending = true; | 
|  | } | 
|  |  | 
|  | if (state == LAN966X_TAPRIO_STATE_OPERATING) { | 
|  | lan966x_taprio_list_state_set(port, | 
|  | LAN966X_TAPRIO_STATE_TERMINATING); | 
|  | operating = true; | 
|  | } | 
|  |  | 
|  | /* If the entry was in pending and now gets in admin, then there | 
|  | * is nothing else to do, so just bail out | 
|  | */ | 
|  | state = lan966x_taprio_list_state_get(port); | 
|  | if (pending && | 
|  | state == LAN966X_TAPRIO_STATE_ADMIN) | 
|  | return 0; | 
|  |  | 
|  | /* If the list was in operating and now is in terminating or | 
|  | * admin, then is OK to exit but it needs to wait until the list | 
|  | * will get in admin. It is not required to set the state | 
|  | * again. | 
|  | */ | 
|  | if (operating && | 
|  | (state == LAN966X_TAPRIO_STATE_TERMINATING || | 
|  | state == LAN966X_TAPRIO_STATE_ADMIN)) | 
|  | break; | 
|  |  | 
|  | } while (!time_after(jiffies, end)); | 
|  |  | 
|  | end = jiffies + msecs_to_jiffies(LAN966X_TAPRIO_TIMEOUT_MS); | 
|  | do { | 
|  | state = lan966x_taprio_list_state_get(port); | 
|  | if (state == LAN966X_TAPRIO_STATE_ADMIN) | 
|  | break; | 
|  |  | 
|  | } while (!time_after(jiffies, end)); | 
|  |  | 
|  | /* If the list was in operating mode, it could be stopped while some | 
|  | * queues where closed, so make sure to restore "all-queues-open" | 
|  | */ | 
|  | if (operating) { | 
|  | lan_wr(QSYS_TAS_GS_CTRL_HSCH_POS_SET(port->chip_port), | 
|  | lan966x, QSYS_TAS_GS_CTRL); | 
|  |  | 
|  | lan_wr(QSYS_TAS_GATE_STATE_TAS_GATE_STATE_SET(0xff), | 
|  | lan966x, QSYS_TAS_GATE_STATE); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int lan966x_taprio_shutdown(struct lan966x_port *port) | 
|  | { | 
|  | u32 i, list, state; | 
|  | int err; | 
|  |  | 
|  | for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) { | 
|  | list = lan966x_taprio_list_index(port, i); | 
|  | state = lan966x_taprio_list_index_state_get(port, list); | 
|  | if (state == LAN966X_TAPRIO_STATE_ADMIN) | 
|  | continue; | 
|  |  | 
|  | err = lan966x_taprio_list_shutdown(port, list); | 
|  | if (err) | 
|  | return err; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Find a suitable list for a new schedule. First priority is a list in state | 
|  | * pending. Second priority is a list in state admin. | 
|  | */ | 
|  | static int lan966x_taprio_find_list(struct lan966x_port *port, | 
|  | struct tc_taprio_qopt_offload *qopt, | 
|  | int *new_list, int *obs_list) | 
|  | { | 
|  | int state[LAN966X_TAPRIO_ENTRIES_PER_PORT]; | 
|  | int list[LAN966X_TAPRIO_ENTRIES_PER_PORT]; | 
|  | int err, oper = -1; | 
|  | u32 i; | 
|  |  | 
|  | *new_list = -1; | 
|  | *obs_list = -1; | 
|  |  | 
|  | /* If there is already an entry in operating mode, return this list in | 
|  | * obs_list, such that when the new list will get activated the | 
|  | * operating list will be stopped. In this way is possible to have | 
|  | * smooth transitions between the lists | 
|  | */ | 
|  | for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) { | 
|  | list[i] = lan966x_taprio_list_index(port, i); | 
|  | state[i] = lan966x_taprio_list_index_state_get(port, list[i]); | 
|  | if (state[i] == LAN966X_TAPRIO_STATE_OPERATING) | 
|  | oper = list[i]; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) { | 
|  | if (state[i] == LAN966X_TAPRIO_STATE_PENDING) { | 
|  | err = lan966x_taprio_shutdown(port); | 
|  | if (err) | 
|  | return err; | 
|  |  | 
|  | *new_list = list[i]; | 
|  | *obs_list = (oper == -1) ? *new_list : oper; | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (i = 0; i < LAN966X_TAPRIO_ENTRIES_PER_PORT; ++i) { | 
|  | if (state[i] == LAN966X_TAPRIO_STATE_ADMIN) { | 
|  | *new_list = list[i]; | 
|  | *obs_list = (oper == -1) ? *new_list : oper; | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | return -ENOSPC; | 
|  | } | 
|  |  | 
|  | static int lan966x_taprio_check(struct tc_taprio_qopt_offload *qopt) | 
|  | { | 
|  | u64 total_time = 0; | 
|  | u32 i; | 
|  |  | 
|  | /* This is not supported by th HW */ | 
|  | if (qopt->cycle_time_extension) | 
|  | return -EOPNOTSUPP; | 
|  |  | 
|  | /* There is a limited number of gcl entries that can be used, they are | 
|  | * shared by all ports | 
|  | */ | 
|  | if (qopt->num_entries > LAN966X_TAPRIO_NUM_GCL) | 
|  | return -EINVAL; | 
|  |  | 
|  | /* Don't allow cycle times bigger than 1 sec or smaller than 1 usec */ | 
|  | if (qopt->cycle_time < LAN966X_TAPRIO_MIN_CYCLE_TIME_NS || | 
|  | qopt->cycle_time > LAN966X_TAPRIO_MAX_CYCLE_TIME_NS) | 
|  | return -EINVAL; | 
|  |  | 
|  | for (i = 0; i < qopt->num_entries; ++i) { | 
|  | struct tc_taprio_sched_entry *entry = &qopt->entries[i]; | 
|  |  | 
|  | /* Don't allow intervals bigger than 1 sec or smaller than 1 | 
|  | * usec | 
|  | */ | 
|  | if (entry->interval < LAN966X_TAPRIO_MIN_CYCLE_TIME_NS || | 
|  | entry->interval > LAN966X_TAPRIO_MAX_CYCLE_TIME_NS) | 
|  | return -EINVAL; | 
|  |  | 
|  | if (qopt->entries[i].command != TC_TAPRIO_CMD_SET_GATES) | 
|  | return -EINVAL; | 
|  |  | 
|  | total_time += qopt->entries[i].interval; | 
|  | } | 
|  |  | 
|  | /* Don't allow the total time of intervals be bigger than 1 sec */ | 
|  | if (total_time > LAN966X_TAPRIO_MAX_CYCLE_TIME_NS) | 
|  | return -EINVAL; | 
|  |  | 
|  | /* The HW expects that the cycle time to be at least as big as sum of | 
|  | * each interval of gcl | 
|  | */ | 
|  | if (qopt->cycle_time < total_time) | 
|  | return -EINVAL; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int lan966x_taprio_gcl_free_get(struct lan966x_port *port, | 
|  | unsigned long *free_list) | 
|  | { | 
|  | struct lan966x *lan966x = port->lan966x; | 
|  | u32 num_free, state, list; | 
|  | u32 base, next, max_list; | 
|  |  | 
|  | /* By default everything is free */ | 
|  | bitmap_fill(free_list, LAN966X_TAPRIO_NUM_GCL); | 
|  | num_free = LAN966X_TAPRIO_NUM_GCL; | 
|  |  | 
|  | /* Iterate over all gcl entries and find out which are free. And mark | 
|  | * those that are not free. | 
|  | */ | 
|  | max_list = lan966x->num_phys_ports * LAN966X_TAPRIO_ENTRIES_PER_PORT; | 
|  | for (list = 0; list < max_list; ++list) { | 
|  | state = lan966x_taprio_list_index_state_get(port, list); | 
|  | if (state == LAN966X_TAPRIO_STATE_ADMIN) | 
|  | continue; | 
|  |  | 
|  | base = lan_rd(lan966x, QSYS_TAS_LIST_CFG); | 
|  | base = QSYS_TAS_LIST_CFG_LIST_BASE_ADDR_GET(base); | 
|  | next = base; | 
|  |  | 
|  | do { | 
|  | clear_bit(next, free_list); | 
|  | num_free--; | 
|  |  | 
|  | lan_rmw(QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM_SET(next), | 
|  | QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM, | 
|  | lan966x, QSYS_TAS_CFG_CTRL); | 
|  |  | 
|  | next = lan_rd(lan966x, QSYS_TAS_GCL_CT_CFG2); | 
|  | next = QSYS_TAS_GCL_CT_CFG2_NEXT_GCL_GET(next); | 
|  | } while (base != next); | 
|  | } | 
|  |  | 
|  | return num_free; | 
|  | } | 
|  |  | 
|  | static void lan966x_taprio_gcl_setup_entry(struct lan966x_port *port, | 
|  | struct tc_taprio_sched_entry *entry, | 
|  | u32 next_entry) | 
|  | { | 
|  | struct lan966x *lan966x = port->lan966x; | 
|  |  | 
|  | /* Setup a single gcl entry */ | 
|  | lan_wr(QSYS_TAS_GCL_CT_CFG_GATE_STATE_SET(entry->gate_mask) | | 
|  | QSYS_TAS_GCL_CT_CFG_HSCH_POS_SET(port->chip_port) | | 
|  | QSYS_TAS_GCL_CT_CFG_OP_TYPE_SET(LAN966X_TAPRIO_GCL_CMD_SET_GATE_STATES), | 
|  | lan966x, QSYS_TAS_GCL_CT_CFG); | 
|  |  | 
|  | lan_wr(QSYS_TAS_GCL_CT_CFG2_PORT_PROFILE_SET(port->chip_port) | | 
|  | QSYS_TAS_GCL_CT_CFG2_NEXT_GCL_SET(next_entry), | 
|  | lan966x, QSYS_TAS_GCL_CT_CFG2); | 
|  |  | 
|  | lan_wr(entry->interval, lan966x, QSYS_TAS_GCL_TM_CFG); | 
|  | } | 
|  |  | 
|  | static int lan966x_taprio_gcl_setup(struct lan966x_port *port, | 
|  | struct tc_taprio_qopt_offload *qopt, | 
|  | int list) | 
|  | { | 
|  | DECLARE_BITMAP(free_list, LAN966X_TAPRIO_NUM_GCL); | 
|  | struct lan966x *lan966x = port->lan966x; | 
|  | u32 i, base, next; | 
|  |  | 
|  | if (lan966x_taprio_gcl_free_get(port, free_list) < qopt->num_entries) | 
|  | return -ENOSPC; | 
|  |  | 
|  | /* Select list */ | 
|  | lan_rmw(QSYS_TAS_CFG_CTRL_LIST_NUM_SET(list), | 
|  | QSYS_TAS_CFG_CTRL_LIST_NUM, | 
|  | lan966x, QSYS_TAS_CFG_CTRL); | 
|  |  | 
|  | /* Setup the address of the first gcl entry */ | 
|  | base = find_first_bit(free_list, LAN966X_TAPRIO_NUM_GCL); | 
|  | lan_rmw(QSYS_TAS_LIST_CFG_LIST_BASE_ADDR_SET(base), | 
|  | QSYS_TAS_LIST_CFG_LIST_BASE_ADDR, | 
|  | lan966x, QSYS_TAS_LIST_CFG); | 
|  |  | 
|  | /* Iterate over entries and add them to the gcl list */ | 
|  | next = base; | 
|  | for (i = 0; i < qopt->num_entries; ++i) { | 
|  | lan_rmw(QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM_SET(next), | 
|  | QSYS_TAS_CFG_CTRL_GCL_ENTRY_NUM, | 
|  | lan966x, QSYS_TAS_CFG_CTRL); | 
|  |  | 
|  | /* If the entry is last, point back to the start of the list */ | 
|  | if (i == qopt->num_entries - 1) | 
|  | next = base; | 
|  | else | 
|  | next = find_next_bit(free_list, LAN966X_TAPRIO_NUM_GCL, | 
|  | next + 1); | 
|  |  | 
|  | lan966x_taprio_gcl_setup_entry(port, &qopt->entries[i], next); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Calculate new base_time based on cycle_time. The HW recommends to have the | 
|  | * new base time at least 2 * cycle type + current time | 
|  | */ | 
|  | static void lan966x_taprio_new_base_time(struct lan966x *lan966x, | 
|  | const u32 cycle_time, | 
|  | const ktime_t org_base_time, | 
|  | ktime_t *new_base_time) | 
|  | { | 
|  | ktime_t current_time, threshold_time; | 
|  | struct timespec64 ts; | 
|  |  | 
|  | /* Get the current time and calculate the threshold_time */ | 
|  | lan966x_ptp_gettime64(&lan966x->phc[LAN966X_PHC_PORT].info, &ts); | 
|  | current_time = timespec64_to_ktime(ts); | 
|  | threshold_time = current_time + (2 * cycle_time); | 
|  |  | 
|  | /* If the org_base_time is in enough in future just use it */ | 
|  | if (org_base_time >= threshold_time) { | 
|  | *new_base_time = org_base_time; | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* If the org_base_time is smaller than current_time, calculate the new | 
|  | * base time as following. | 
|  | */ | 
|  | if (org_base_time <= current_time) { | 
|  | u64 tmp = current_time - org_base_time; | 
|  | u32 rem = 0; | 
|  |  | 
|  | if (tmp > cycle_time) | 
|  | div_u64_rem(tmp, cycle_time, &rem); | 
|  | rem = cycle_time - rem; | 
|  | *new_base_time = threshold_time + rem; | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* The only left place for org_base_time is between current_time and | 
|  | * threshold_time. In this case the new_base_time is calculated like | 
|  | * org_base_time + 2 * cycletime | 
|  | */ | 
|  | *new_base_time = org_base_time + 2 * cycle_time; | 
|  | } | 
|  |  | 
|  | int lan966x_taprio_speed_set(struct lan966x_port *port, int speed) | 
|  | { | 
|  | struct lan966x *lan966x = port->lan966x; | 
|  | u8 taprio_speed; | 
|  |  | 
|  | switch (speed) { | 
|  | case SPEED_10: | 
|  | taprio_speed = LAN966X_TAPRIO_SPEED_10; | 
|  | break; | 
|  | case SPEED_100: | 
|  | taprio_speed = LAN966X_TAPRIO_SPEED_100; | 
|  | break; | 
|  | case SPEED_1000: | 
|  | taprio_speed = LAN966X_TAPRIO_SPEED_1000; | 
|  | break; | 
|  | case SPEED_2500: | 
|  | taprio_speed = LAN966X_TAPRIO_SPEED_2500; | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | lan_rmw(QSYS_TAS_PROFILE_CFG_LINK_SPEED_SET(taprio_speed), | 
|  | QSYS_TAS_PROFILE_CFG_LINK_SPEED, | 
|  | lan966x, QSYS_TAS_PROFILE_CFG(port->chip_port)); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int lan966x_taprio_add(struct lan966x_port *port, | 
|  | struct tc_taprio_qopt_offload *qopt) | 
|  | { | 
|  | struct lan966x *lan966x = port->lan966x; | 
|  | int err, new_list, obs_list; | 
|  | struct timespec64 ts; | 
|  | ktime_t base_time; | 
|  |  | 
|  | err = lan966x_taprio_check(qopt); | 
|  | if (err) | 
|  | return err; | 
|  |  | 
|  | err = lan966x_taprio_find_list(port, qopt, &new_list, &obs_list); | 
|  | if (err) | 
|  | return err; | 
|  |  | 
|  | err = lan966x_taprio_gcl_setup(port, qopt, new_list); | 
|  | if (err) | 
|  | return err; | 
|  |  | 
|  | lan966x_taprio_new_base_time(lan966x, qopt->cycle_time, | 
|  | qopt->base_time, &base_time); | 
|  |  | 
|  | ts = ktime_to_timespec64(base_time); | 
|  | lan_wr(QSYS_TAS_BT_NSEC_NSEC_SET(ts.tv_nsec), | 
|  | lan966x, QSYS_TAS_BT_NSEC); | 
|  |  | 
|  | lan_wr(lower_32_bits(ts.tv_sec), | 
|  | lan966x, QSYS_TAS_BT_SEC_LSB); | 
|  |  | 
|  | lan_wr(QSYS_TAS_BT_SEC_MSB_SEC_MSB_SET(upper_32_bits(ts.tv_sec)), | 
|  | lan966x, QSYS_TAS_BT_SEC_MSB); | 
|  |  | 
|  | lan_wr(qopt->cycle_time, lan966x, QSYS_TAS_CT_CFG); | 
|  |  | 
|  | lan_rmw(QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX_SET(obs_list), | 
|  | QSYS_TAS_STARTUP_CFG_OBSOLETE_IDX, | 
|  | lan966x, QSYS_TAS_STARTUP_CFG); | 
|  |  | 
|  | /* Start list processing */ | 
|  | lan_rmw(QSYS_TAS_LST_LIST_STATE_SET(LAN966X_TAPRIO_STATE_ADVANCING), | 
|  | QSYS_TAS_LST_LIST_STATE, | 
|  | lan966x, QSYS_TAS_LST); | 
|  |  | 
|  | return err; | 
|  | } | 
|  |  | 
|  | int lan966x_taprio_del(struct lan966x_port *port) | 
|  | { | 
|  | return lan966x_taprio_shutdown(port); | 
|  | } | 
|  |  | 
|  | void lan966x_taprio_init(struct lan966x *lan966x) | 
|  | { | 
|  | int num_taprio_lists; | 
|  | int p; | 
|  |  | 
|  | lan_wr(QSYS_TAS_STM_CFG_REVISIT_DLY_SET((256 * 1000) / | 
|  | lan966x_ptp_get_period_ps()), | 
|  | lan966x, QSYS_TAS_STM_CFG); | 
|  |  | 
|  | num_taprio_lists = lan966x->num_phys_ports * | 
|  | LAN966X_TAPRIO_ENTRIES_PER_PORT; | 
|  |  | 
|  | /* For now we always use guard band on all queues */ | 
|  | lan_rmw(QSYS_TAS_CFG_CTRL_LIST_NUM_MAX_SET(num_taprio_lists) | | 
|  | QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q_SET(1), | 
|  | QSYS_TAS_CFG_CTRL_LIST_NUM_MAX | | 
|  | QSYS_TAS_CFG_CTRL_ALWAYS_GB_SCH_Q, | 
|  | lan966x, QSYS_TAS_CFG_CTRL); | 
|  |  | 
|  | for (p = 0; p < lan966x->num_phys_ports; p++) | 
|  | lan_rmw(QSYS_TAS_PROFILE_CFG_PORT_NUM_SET(p), | 
|  | QSYS_TAS_PROFILE_CFG_PORT_NUM, | 
|  | lan966x, QSYS_TAS_PROFILE_CFG(p)); | 
|  | } | 
|  |  | 
|  | void lan966x_taprio_deinit(struct lan966x *lan966x) | 
|  | { | 
|  | int p; | 
|  |  | 
|  | for (p = 0; p < lan966x->num_phys_ports; ++p) { | 
|  | if (!lan966x->ports[p]) | 
|  | continue; | 
|  |  | 
|  | lan966x_taprio_del(lan966x->ports[p]); | 
|  | } | 
|  | } |