2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2017-05-01 14:05:12 -04:00
/*
* Marvell 88E6 xxx VLAN [ Spanning Tree ] Translation Unit ( VTU [ STU ] ) support
*
* Copyright ( c ) 2008 Marvell Semiconductor
* Copyright ( c ) 2015 CMC Electronics , Inc .
* Copyright ( c ) 2017 Savoir - faire Linux , Inc .
*/
2019-08-09 18:47:55 -04:00
# include <linux/bitfield.h>
2018-01-14 02:32:45 +01:00
# include <linux/interrupt.h>
# include <linux/irqdomain.h>
2017-06-02 17:06:15 -04:00
# include "chip.h"
2017-05-01 14:05:12 -04:00
# include "global1.h"
2017-05-01 14:05:14 -04:00
/* Offset 0x02: VTU FID Register */
2017-05-01 14:05:24 -04:00
static int mv88e6xxx_g1_vtu_fid_read ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
2017-05-01 14:05:14 -04:00
{
u16 val ;
int err ;
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_read ( chip , MV88E6352_G1_VTU_FID , & val ) ;
2017-05-01 14:05:14 -04:00
if ( err )
return err ;
2017-06-15 12:14:02 -04:00
entry - > fid = val & MV88E6352_G1_VTU_FID_MASK ;
2017-05-01 14:05:14 -04:00
return 0 ;
}
2017-05-01 14:05:24 -04:00
static int mv88e6xxx_g1_vtu_fid_write ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
2017-05-01 14:05:14 -04:00
{
2017-06-15 12:14:02 -04:00
u16 val = entry - > fid & MV88E6352_G1_VTU_FID_MASK ;
2017-05-01 14:05:14 -04:00
2017-06-15 12:14:02 -04:00
return mv88e6xxx_g1_write ( chip , MV88E6352_G1_VTU_FID , val ) ;
2017-05-01 14:05:14 -04:00
}
2017-05-01 14:05:15 -04:00
/* Offset 0x03: VTU SID Register */
2017-05-01 14:05:24 -04:00
static int mv88e6xxx_g1_vtu_sid_read ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
2017-05-01 14:05:15 -04:00
{
u16 val ;
int err ;
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_read ( chip , MV88E6352_G1_VTU_SID , & val ) ;
2017-05-01 14:05:15 -04:00
if ( err )
return err ;
2017-06-15 12:14:02 -04:00
entry - > sid = val & MV88E6352_G1_VTU_SID_MASK ;
2017-05-01 14:05:15 -04:00
return 0 ;
}
2017-05-01 14:05:24 -04:00
static int mv88e6xxx_g1_vtu_sid_write ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
2017-05-01 14:05:15 -04:00
{
2017-06-15 12:14:02 -04:00
u16 val = entry - > sid & MV88E6352_G1_VTU_SID_MASK ;
2017-05-01 14:05:15 -04:00
2017-06-15 12:14:02 -04:00
return mv88e6xxx_g1_write ( chip , MV88E6352_G1_VTU_SID , val ) ;
2017-05-01 14:05:15 -04:00
}
2017-05-01 14:05:12 -04:00
/* Offset 0x05: VTU Operation Register */
2017-05-01 14:05:24 -04:00
static int mv88e6xxx_g1_vtu_op_wait ( struct mv88e6xxx_chip * chip )
2017-05-01 14:05:12 -04:00
{
2019-08-09 18:47:55 -04:00
int bit = __bf_shf ( MV88E6XXX_G1_VTU_OP_BUSY ) ;
return mv88e6xxx_g1_wait_bit ( chip , MV88E6XXX_G1_VTU_OP , bit , 0 ) ;
2017-05-01 14:05:12 -04:00
}
2017-05-01 14:05:24 -04:00
static int mv88e6xxx_g1_vtu_op ( struct mv88e6xxx_chip * chip , u16 op )
2017-05-01 14:05:12 -04:00
{
int err ;
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_write ( chip , MV88E6XXX_G1_VTU_OP ,
MV88E6XXX_G1_VTU_OP_BUSY | op ) ;
2017-05-01 14:05:12 -04:00
if ( err )
return err ;
return mv88e6xxx_g1_vtu_op_wait ( chip ) ;
}
2017-05-01 14:05:13 -04:00
2017-05-01 14:05:16 -04:00
/* Offset 0x06: VTU VID Register */
2017-05-01 14:05:24 -04:00
static int mv88e6xxx_g1_vtu_vid_read ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
2017-05-01 14:05:16 -04:00
{
u16 val ;
int err ;
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_read ( chip , MV88E6XXX_G1_VTU_VID , & val ) ;
2017-05-01 14:05:16 -04:00
if ( err )
return err ;
entry - > vid = val & 0xfff ;
2017-05-01 14:05:26 -04:00
2017-06-15 12:14:02 -04:00
if ( val & MV88E6390_G1_VTU_VID_PAGE )
2017-05-01 14:05:26 -04:00
entry - > vid | = 0x1000 ;
2017-06-15 12:14:02 -04:00
entry - > valid = ! ! ( val & MV88E6XXX_G1_VTU_VID_VALID ) ;
2017-05-01 14:05:16 -04:00
return 0 ;
}
2017-05-01 14:05:24 -04:00
static int mv88e6xxx_g1_vtu_vid_write ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
2017-05-01 14:05:16 -04:00
{
u16 val = entry - > vid & 0xfff ;
2017-05-01 14:05:26 -04:00
if ( entry - > vid & 0x1000 )
2017-06-15 12:14:02 -04:00
val | = MV88E6390_G1_VTU_VID_PAGE ;
2017-05-01 14:05:26 -04:00
2017-05-01 14:05:16 -04:00
if ( entry - > valid )
2017-06-15 12:14:02 -04:00
val | = MV88E6XXX_G1_VTU_VID_VALID ;
2017-05-01 14:05:16 -04:00
2017-06-15 12:14:02 -04:00
return mv88e6xxx_g1_write ( chip , MV88E6XXX_G1_VTU_VID , val ) ;
2017-05-01 14:05:16 -04:00
}
2017-05-01 14:05:18 -04:00
/* Offset 0x07: VTU/STU Data Register 1
* Offset 0x08 : VTU / STU Data Register 2
* Offset 0x09 : VTU / STU Data Register 3
*/
2020-11-12 12:43:35 +01:00
static int mv88e6185_g1_vtu_stu_data_read ( struct mv88e6xxx_chip * chip ,
u16 * regs )
2017-05-01 14:05:18 -04:00
{
int i ;
/* Read all 3 VTU/STU Data registers */
for ( i = 0 ; i < 3 ; + + i ) {
u16 * reg = & regs [ i ] ;
int err ;
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_read ( chip , MV88E6XXX_G1_VTU_DATA1 + i , reg ) ;
2017-05-01 14:05:18 -04:00
if ( err )
return err ;
}
2020-11-12 12:43:35 +01:00
return 0 ;
}
static int mv88e6185_g1_vtu_data_read ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
{
u16 regs [ 3 ] ;
int err ;
int i ;
err = mv88e6185_g1_vtu_stu_data_read ( chip , regs ) ;
if ( err )
return err ;
/* Extract MemberTag data */
2017-05-01 14:05:18 -04:00
for ( i = 0 ; i < mv88e6xxx_num_ports ( chip ) ; + + i ) {
unsigned int member_offset = ( i % 4 ) * 4 ;
entry - > member [ i ] = ( regs [ i / 4 ] > > member_offset ) & 0x3 ;
2020-11-12 12:43:35 +01:00
}
return 0 ;
}
static int mv88e6185_g1_stu_data_read ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
{
u16 regs [ 3 ] ;
int err ;
int i ;
err = mv88e6185_g1_vtu_stu_data_read ( chip , regs ) ;
if ( err )
return err ;
/* Extract PortState data */
for ( i = 0 ; i < mv88e6xxx_num_ports ( chip ) ; + + i ) {
unsigned int state_offset = ( i % 4 ) * 4 + 2 ;
2017-05-01 14:05:18 -04:00
entry - > state [ i ] = ( regs [ i / 4 ] > > state_offset ) & 0x3 ;
}
return 0 ;
}
2017-05-01 14:05:24 -04:00
static int mv88e6185_g1_vtu_data_write ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
2017-05-01 14:05:18 -04:00
{
u16 regs [ 3 ] = { 0 } ;
int i ;
/* Insert MemberTag and PortState data */
for ( i = 0 ; i < mv88e6xxx_num_ports ( chip ) ; + + i ) {
unsigned int member_offset = ( i % 4 ) * 4 ;
unsigned int state_offset = member_offset + 2 ;
regs [ i / 4 ] | = ( entry - > member [ i ] & 0x3 ) < < member_offset ;
regs [ i / 4 ] | = ( entry - > state [ i ] & 0x3 ) < < state_offset ;
}
/* Write all 3 VTU/STU Data registers */
for ( i = 0 ; i < 3 ; + + i ) {
u16 reg = regs [ i ] ;
int err ;
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_write ( chip , MV88E6XXX_G1_VTU_DATA1 + i , reg ) ;
2017-05-01 14:05:18 -04:00
if ( err )
return err ;
}
return 0 ;
}
2017-05-01 14:05:27 -04:00
static int mv88e6390_g1_vtu_data_read ( struct mv88e6xxx_chip * chip , u8 * data )
{
u16 regs [ 2 ] ;
int i ;
/* Read the 2 VTU/STU Data registers */
for ( i = 0 ; i < 2 ; + + i ) {
u16 * reg = & regs [ i ] ;
int err ;
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_read ( chip , MV88E6XXX_G1_VTU_DATA1 + i , reg ) ;
2017-05-01 14:05:27 -04:00
if ( err )
return err ;
}
/* Extract data */
for ( i = 0 ; i < mv88e6xxx_num_ports ( chip ) ; + + i ) {
unsigned int offset = ( i % 8 ) * 2 ;
data [ i ] = ( regs [ i / 8 ] > > offset ) & 0x3 ;
}
return 0 ;
}
static int mv88e6390_g1_vtu_data_write ( struct mv88e6xxx_chip * chip , u8 * data )
{
u16 regs [ 2 ] = { 0 } ;
int i ;
/* Insert data */
for ( i = 0 ; i < mv88e6xxx_num_ports ( chip ) ; + + i ) {
unsigned int offset = ( i % 8 ) * 2 ;
regs [ i / 8 ] | = ( data [ i ] & 0x3 ) < < offset ;
}
/* Write the 2 VTU/STU Data registers */
for ( i = 0 ; i < 2 ; + + i ) {
u16 reg = regs [ i ] ;
int err ;
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_write ( chip , MV88E6XXX_G1_VTU_DATA1 + i , reg ) ;
2017-05-01 14:05:27 -04:00
if ( err )
return err ;
}
return 0 ;
}
2017-05-01 14:05:13 -04:00
/* VLAN Translation Unit Operations */
2017-05-01 14:05:24 -04:00
static int mv88e6xxx_g1_vtu_stu_getnext ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
2017-05-01 14:05:19 -04:00
{
int err ;
err = mv88e6xxx_g1_vtu_sid_write ( chip , entry ) ;
if ( err )
return err ;
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_vtu_op ( chip , MV88E6XXX_G1_VTU_OP_STU_GET_NEXT ) ;
2017-05-01 14:05:19 -04:00
if ( err )
return err ;
err = mv88e6xxx_g1_vtu_sid_read ( chip , entry ) ;
if ( err )
return err ;
return mv88e6xxx_g1_vtu_vid_read ( chip , entry ) ;
}
2017-05-01 14:05:24 -04:00
static int mv88e6xxx_g1_vtu_stu_get ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * vtu )
2017-05-01 14:05:20 -04:00
{
struct mv88e6xxx_vtu_entry stu ;
int err ;
err = mv88e6xxx_g1_vtu_sid_read ( chip , vtu ) ;
if ( err )
return err ;
stu . sid = vtu - > sid - 1 ;
err = mv88e6xxx_g1_vtu_stu_getnext ( chip , & stu ) ;
if ( err )
return err ;
if ( stu . sid ! = vtu - > sid | | ! stu . valid )
return - EINVAL ;
return 0 ;
}
2020-11-09 09:29:27 +01:00
int mv88e6xxx_g1_vtu_getnext ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
2017-05-01 14:05:17 -04:00
{
int err ;
err = mv88e6xxx_g1_vtu_op_wait ( chip ) ;
if ( err )
return err ;
/* To get the next higher active VID, the VTU GetNext operation can be
* started again without setting the VID registers since it already
* contains the last VID .
*
* To save a few hardware accesses and abstract this to the caller ,
* write the VID only once , when the entry is given as invalid .
*/
if ( ! entry - > valid ) {
err = mv88e6xxx_g1_vtu_vid_write ( chip , entry ) ;
if ( err )
return err ;
}
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_vtu_op ( chip , MV88E6XXX_G1_VTU_OP_VTU_GET_NEXT ) ;
2017-05-01 14:05:17 -04:00
if ( err )
return err ;
return mv88e6xxx_g1_vtu_vid_read ( chip , entry ) ;
}
2017-05-01 14:05:22 -04:00
int mv88e6185_g1_vtu_getnext ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
{
u16 val ;
int err ;
err = mv88e6xxx_g1_vtu_getnext ( chip , entry ) ;
if ( err )
return err ;
if ( entry - > valid ) {
err = mv88e6185_g1_vtu_data_read ( chip , entry ) ;
if ( err )
return err ;
2020-11-12 12:43:35 +01:00
err = mv88e6185_g1_stu_data_read ( chip , entry ) ;
if ( err )
return err ;
2017-05-01 14:05:22 -04:00
/* VTU DBNum[3:0] are located in VTU Operation 3:0
2021-01-25 16:04:48 +01:00
* VTU DBNum [ 7 : 4 ] ( [ 5 : 4 ] for 6250 ) are located in VTU Operation 11 : 8 ( 9 : 8 )
2017-05-01 14:05:22 -04:00
*/
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_read ( chip , MV88E6XXX_G1_VTU_OP , & val ) ;
2017-05-01 14:05:22 -04:00
if ( err )
return err ;
entry - > fid = val & 0x000f ;
entry - > fid | = ( val & 0x0f00 ) > > 4 ;
2021-01-25 16:04:48 +01:00
entry - > fid & = mv88e6xxx_num_databases ( chip ) - 1 ;
2017-05-01 14:05:22 -04:00
}
return 0 ;
}
int mv88e6352_g1_vtu_getnext ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
{
int err ;
/* Fetch VLAN MemberTag data from the VTU */
err = mv88e6xxx_g1_vtu_getnext ( chip , entry ) ;
if ( err )
return err ;
if ( entry - > valid ) {
2020-11-12 12:43:35 +01:00
err = mv88e6185_g1_vtu_data_read ( chip , entry ) ;
2017-05-01 14:05:22 -04:00
if ( err )
return err ;
2020-11-12 12:43:35 +01:00
err = mv88e6xxx_g1_vtu_fid_read ( chip , entry ) ;
2017-05-01 14:05:22 -04:00
if ( err )
return err ;
2020-11-12 12:43:35 +01:00
/* Fetch VLAN PortState data from the STU */
err = mv88e6xxx_g1_vtu_stu_get ( chip , entry ) ;
if ( err )
return err ;
err = mv88e6185_g1_stu_data_read ( chip , entry ) ;
2017-05-01 14:05:22 -04:00
if ( err )
return err ;
}
return 0 ;
}
2017-05-01 14:05:27 -04:00
int mv88e6390_g1_vtu_getnext ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
{
int err ;
/* Fetch VLAN MemberTag data from the VTU */
err = mv88e6xxx_g1_vtu_getnext ( chip , entry ) ;
if ( err )
return err ;
if ( entry - > valid ) {
err = mv88e6390_g1_vtu_data_read ( chip , entry - > member ) ;
if ( err )
return err ;
/* Fetch VLAN PortState data from the STU */
err = mv88e6xxx_g1_vtu_stu_get ( chip , entry ) ;
if ( err )
return err ;
err = mv88e6390_g1_vtu_data_read ( chip , entry - > state ) ;
if ( err )
return err ;
err = mv88e6xxx_g1_vtu_fid_read ( chip , entry ) ;
if ( err )
return err ;
}
return 0 ;
}
2017-05-01 14:05:23 -04:00
int mv88e6185_g1_vtu_loadpurge ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
{
2017-06-15 12:14:02 -04:00
u16 op = MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE ;
2017-05-01 14:05:23 -04:00
int err ;
err = mv88e6xxx_g1_vtu_op_wait ( chip ) ;
if ( err )
return err ;
err = mv88e6xxx_g1_vtu_vid_write ( chip , entry ) ;
if ( err )
return err ;
if ( entry - > valid ) {
err = mv88e6185_g1_vtu_data_write ( chip , entry ) ;
if ( err )
return err ;
/* VTU DBNum[3:0] are located in VTU Operation 3:0
* VTU DBNum [ 7 : 4 ] are located in VTU Operation 11 : 8
2021-01-25 16:04:49 +01:00
*
* For the 6250 / 6220 , the latter are really [ 5 : 4 ] and
* 9 : 8 , but in those cases bits 7 : 6 of entry - > fid are
* 0 since they have num_databases = 64.
2017-05-01 14:05:23 -04:00
*/
op | = entry - > fid & 0x000f ;
2019-06-19 10:02:13 +00:00
op | = ( entry - > fid & 0x00f0 ) < < 4 ;
2017-05-01 14:05:23 -04:00
}
return mv88e6xxx_g1_vtu_op ( chip , op ) ;
}
int mv88e6352_g1_vtu_loadpurge ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
{
int err ;
err = mv88e6xxx_g1_vtu_op_wait ( chip ) ;
if ( err )
return err ;
err = mv88e6xxx_g1_vtu_vid_write ( chip , entry ) ;
if ( err )
return err ;
if ( entry - > valid ) {
/* Write MemberTag and PortState data */
err = mv88e6185_g1_vtu_data_write ( chip , entry ) ;
if ( err )
return err ;
err = mv88e6xxx_g1_vtu_sid_write ( chip , entry ) ;
if ( err )
return err ;
/* Load STU entry */
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_vtu_op ( chip ,
MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE ) ;
2017-05-01 14:05:23 -04:00
if ( err )
return err ;
err = mv88e6xxx_g1_vtu_fid_write ( chip , entry ) ;
if ( err )
return err ;
}
/* Load/Purge VTU entry */
2017-06-15 12:14:02 -04:00
return mv88e6xxx_g1_vtu_op ( chip , MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE ) ;
2017-05-01 14:05:23 -04:00
}
2017-05-01 14:05:27 -04:00
int mv88e6390_g1_vtu_loadpurge ( struct mv88e6xxx_chip * chip ,
struct mv88e6xxx_vtu_entry * entry )
{
int err ;
err = mv88e6xxx_g1_vtu_op_wait ( chip ) ;
if ( err )
return err ;
err = mv88e6xxx_g1_vtu_vid_write ( chip , entry ) ;
if ( err )
return err ;
if ( entry - > valid ) {
/* Write PortState data */
err = mv88e6390_g1_vtu_data_write ( chip , entry - > state ) ;
if ( err )
return err ;
err = mv88e6xxx_g1_vtu_sid_write ( chip , entry ) ;
if ( err )
return err ;
/* Load STU entry */
2017-06-15 12:14:02 -04:00
err = mv88e6xxx_g1_vtu_op ( chip ,
MV88E6XXX_G1_VTU_OP_STU_LOAD_PURGE ) ;
2017-05-01 14:05:27 -04:00
if ( err )
return err ;
/* Write MemberTag data */
err = mv88e6390_g1_vtu_data_write ( chip , entry - > member ) ;
if ( err )
return err ;
err = mv88e6xxx_g1_vtu_fid_write ( chip , entry ) ;
if ( err )
return err ;
}
/* Load/Purge VTU entry */
2017-06-15 12:14:02 -04:00
return mv88e6xxx_g1_vtu_op ( chip , MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE ) ;
2017-05-01 14:05:27 -04:00
}
2017-05-01 14:05:13 -04:00
int mv88e6xxx_g1_vtu_flush ( struct mv88e6xxx_chip * chip )
{
int err ;
err = mv88e6xxx_g1_vtu_op_wait ( chip ) ;
if ( err )
return err ;
2017-06-15 12:14:02 -04:00
return mv88e6xxx_g1_vtu_op ( chip , MV88E6XXX_G1_VTU_OP_FLUSH_ALL ) ;
2017-05-01 14:05:13 -04:00
}
2018-01-14 02:32:45 +01:00
static irqreturn_t mv88e6xxx_g1_vtu_prob_irq_thread_fn ( int irq , void * dev_id )
{
struct mv88e6xxx_chip * chip = dev_id ;
struct mv88e6xxx_vtu_entry entry ;
int spid ;
int err ;
u16 val ;
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_lock ( chip ) ;
2018-01-14 02:32:45 +01:00
err = mv88e6xxx_g1_vtu_op ( chip , MV88E6XXX_G1_VTU_OP_GET_CLR_VIOLATION ) ;
if ( err )
goto out ;
err = mv88e6xxx_g1_read ( chip , MV88E6XXX_G1_VTU_OP , & val ) ;
if ( err )
goto out ;
err = mv88e6xxx_g1_vtu_vid_read ( chip , & entry ) ;
if ( err )
goto out ;
spid = val & MV88E6XXX_G1_VTU_OP_SPID_MASK ;
if ( val & MV88E6XXX_G1_VTU_OP_MEMBER_VIOLATION ) {
dev_err_ratelimited ( chip - > dev , " VTU member violation for vid %d, source port %d \n " ,
entry . vid , spid ) ;
2018-03-28 23:50:28 +02:00
chip - > ports [ spid ] . vtu_member_violation + + ;
2018-01-14 02:32:45 +01:00
}
2018-03-28 23:50:28 +02:00
if ( val & MV88E6XXX_G1_VTU_OP_MISS_VIOLATION ) {
2018-03-28 23:50:29 +02:00
dev_dbg_ratelimited ( chip - > dev , " VTU miss violation for vid %d, source port %d \n " ,
2018-01-14 02:32:45 +01:00
entry . vid , spid ) ;
2018-03-28 23:50:28 +02:00
chip - > ports [ spid ] . vtu_miss_violation + + ;
}
2018-03-28 23:50:29 +02:00
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_unlock ( chip ) ;
2018-01-14 02:32:45 +01:00
return IRQ_HANDLED ;
out :
2019-06-20 13:50:42 +00:00
mv88e6xxx_reg_unlock ( chip ) ;
2018-01-14 02:32:45 +01:00
dev_err ( chip - > dev , " VTU problem: error %d while handling interrupt \n " ,
err ) ;
return IRQ_HANDLED ;
}
int mv88e6xxx_g1_vtu_prob_irq_setup ( struct mv88e6xxx_chip * chip )
{
int err ;
chip - > vtu_prob_irq = irq_find_mapping ( chip - > g1_irq . domain ,
MV88E6XXX_G1_STS_IRQ_VTU_PROB ) ;
if ( chip - > vtu_prob_irq < 0 )
2018-01-18 17:42:49 +01:00
return chip - > vtu_prob_irq ;
2018-01-14 02:32:45 +01:00
2020-01-06 17:13:52 +01:00
snprintf ( chip - > vtu_prob_irq_name , sizeof ( chip - > vtu_prob_irq_name ) ,
" mv88e6xxx-%s-g1-vtu-prob " , dev_name ( chip - > dev ) ) ;
2018-01-14 02:32:45 +01:00
err = request_threaded_irq ( chip - > vtu_prob_irq , NULL ,
mv88e6xxx_g1_vtu_prob_irq_thread_fn ,
2020-01-06 17:13:52 +01:00
IRQF_ONESHOT , chip - > vtu_prob_irq_name ,
2018-01-14 02:32:45 +01:00
chip ) ;
if ( err )
irq_dispose_mapping ( chip - > vtu_prob_irq ) ;
return err ;
}
void mv88e6xxx_g1_vtu_prob_irq_free ( struct mv88e6xxx_chip * chip )
{
free_irq ( chip - > vtu_prob_irq , chip ) ;
irq_dispose_mapping ( chip - > vtu_prob_irq ) ;
}