diff options
author | 2023-02-21 18:24:12 -0800 | |
---|---|---|
committer | 2023-02-21 18:24:12 -0800 | |
commit | 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 (patch) | |
tree | cc5c2d0a898769fd59549594fedb3ee6f84e59a0 /drivers/rapidio/switches | |
download | linux-5b7c4cabbb65f5c469464da6c5f614cbd7f730f2.tar.gz linux-5b7c4cabbb65f5c469464da6c5f614cbd7f730f2.zip |
Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-nextgrafted
Pull networking updates from Jakub Kicinski:
"Core:
- Add dedicated kmem_cache for typical/small skb->head, avoid having
to access struct page at kfree time, and improve memory use.
- Introduce sysctl to set default RPS configuration for new netdevs.
- Define Netlink protocol specification format which can be used to
describe messages used by each family and auto-generate parsers.
Add tools for generating kernel data structures and uAPI headers.
- Expose all net/core sysctls inside netns.
- Remove 4s sleep in netpoll if carrier is instantly detected on
boot.
- Add configurable limit of MDB entries per port, and port-vlan.
- Continue populating drop reasons throughout the stack.
- Retire a handful of legacy Qdiscs and classifiers.
Protocols:
- Support IPv4 big TCP (TSO frames larger than 64kB).
- Add IP_LOCAL_PORT_RANGE socket option, to control local port range
on socket by socket basis.
- Track and report in procfs number of MPTCP sockets used.
- Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path
manager.
- IPv6: don't check net.ipv6.route.max_size and rely on garbage
collection to free memory (similarly to IPv4).
- Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986).
- ICMP: add per-rate limit counters.
- Add support for user scanning requests in ieee802154.
- Remove static WEP support.
- Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate
reporting.
- WiFi 7 EHT channel puncturing support (client & AP).
BPF:
- Add a rbtree data structure following the "next-gen data structure"
precedent set by recently added linked list, that is, by using
kfunc + kptr instead of adding a new BPF map type.
- Expose XDP hints via kfuncs with initial support for RX hash and
timestamp metadata.
- Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to
better support decap on GRE tunnel devices not operating in collect
metadata.
- Improve x86 JIT's codegen for PROBE_MEM runtime error checks.
- Remove the need for trace_printk_lock for bpf_trace_printk and
bpf_trace_vprintk helpers.
- Extend libbpf's bpf_tracing.h support for tracing arguments of
kprobes/uprobes and syscall as a special case.
- Significantly reduce the search time for module symbols by
livepatch and BPF.
- Enable cpumasks to be used as kptrs, which is useful for tracing
programs tracking which tasks end up running on which CPUs in
different time intervals.
- Add support for BPF trampoline on s390x and riscv64.
- Add capability to export the XDP features supported by the NIC.
- Add __bpf_kfunc tag for marking kernel functions as kfuncs.
- Add cgroup.memory=nobpf kernel parameter option to disable BPF
memory accounting for container environments.
Netfilter:
- Remove the CLUSTERIP target. It has been marked as obsolete for
years, and we still have WARN splats wrt races of the out-of-band
/proc interface installed by this target.
- Add 'destroy' commands to nf_tables. They are identical to the
existing 'delete' commands, but do not return an error if the
referenced object (set, chain, rule...) did not exist.
Driver API:
- Improve cpumask_local_spread() locality to help NICs set the right
IRQ affinity on AMD platforms.
- Separate C22 and C45 MDIO bus transactions more clearly.
- Introduce new DCB table to control DSCP rewrite on egress.
- Support configuration of Physical Layer Collision Avoidance (PLCA)
Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of
shared medium Ethernet.
- Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing
preemption of low priority frames by high priority frames.
- Add support for controlling MACSec offload using netlink SET.
- Rework devlink instance refcounts to allow registration and
de-registration under the instance lock. Split the code into
multiple files, drop some of the unnecessarily granular locks and
factor out common parts of netlink operation handling.
- Add TX frame aggregation parameters (for USB drivers).
- Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning
messages with notifications for debug.
- Allow offloading of UDP NEW connections via act_ct.
- Add support for per action HW stats in TC.
- Support hardware miss to TC action (continue processing in SW from
a specific point in the action chain).
- Warn if old Wireless Extension user space interface is used with
modern cfg80211/mac80211 drivers. Do not support Wireless
Extensions for Wi-Fi 7 devices at all. Everyone should switch to
using nl80211 interface instead.
- Improve the CAN bit timing configuration. Use extack to return
error messages directly to user space, update the SJW handling,
including the definition of a new default value that will benefit
CAN-FD controllers, by increasing their oscillator tolerance.
New hardware / drivers:
- Ethernet:
- nVidia BlueField-3 support (control traffic driver)
- Ethernet support for imx93 SoCs
- Motorcomm yt8531 gigabit Ethernet PHY
- onsemi NCN26000 10BASE-T1S PHY (with support for PLCA)
- Microchip LAN8841 PHY (incl. cable diagnostics and PTP)
- Amlogic gxl MDIO mux
- WiFi:
- RealTek RTL8188EU (rtl8xxxu)
- Qualcomm Wi-Fi 7 devices (ath12k)
- CAN:
- Renesas R-Car V4H
Drivers:
- Bluetooth:
- Set Per Platform Antenna Gain (PPAG) for Intel controllers.
- Ethernet NICs:
- Intel (1G, igc):
- support TSN / Qbv / packet scheduling features of i226 model
- Intel (100G, ice):
- use GNSS subsystem instead of TTY
- multi-buffer XDP support
- extend support for GPIO pins to E823 devices
- nVidia/Mellanox:
- update the shared buffer configuration on PFC commands
- implement PTP adjphase function for HW offset control
- TC support for Geneve and GRE with VF tunnel offload
- more efficient crypto key management method
- multi-port eswitch support
- Netronome/Corigine:
- add DCB IEEE support
- support IPsec offloading for NFP3800
- Freescale/NXP (enetc):
- support XDP_REDIRECT for XDP non-linear buffers
- improve reconfig, avoid link flap and waiting for idle
- support MAC Merge layer
- Other NICs:
- sfc/ef100: add basic devlink support for ef100
- ionic: rx_push mode operation (writing descriptors via MMIO)
- bnxt: use the auxiliary bus abstraction for RDMA
- r8169: disable ASPM and reset bus in case of tx timeout
- cpsw: support QSGMII mode for J721e CPSW9G
- cpts: support pulse-per-second output
- ngbe: add an mdio bus driver
- usbnet: optimize usbnet_bh() by avoiding unnecessary queuing
- r8152: handle devices with FW with NCM support
- amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation
- virtio-net: support multi buffer XDP
- virtio/vsock: replace virtio_vsock_pkt with sk_buff
- tsnep: XDP support
- Ethernet high-speed switches:
- nVidia/Mellanox (mlxsw):
- add support for latency TLV (in FW control messages)
- Microchip (sparx5):
- separate explicit and implicit traffic forwarding rules, make
the implicit rules always active
- add support for egress DSCP rewrite
- IS0 VCAP support (Ingress Classification)
- IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS
etc.)
- ES2 VCAP support (Egress Access Control)
- support for Per-Stream Filtering and Policing (802.1Q,
8.6.5.1)
- Ethernet embedded switches:
- Marvell (mv88e6xxx):
- add MAB (port auth) offload support
- enable PTP receive for mv88e6390
- NXP (ocelot):
- support MAC Merge layer
- support for the the vsc7512 internal copper phys
- Microchip:
- lan9303: convert to PHYLINK
- lan966x: support TC flower filter statistics
- lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x
- lan937x: support Credit Based Shaper configuration
- ksz9477: support Energy Efficient Ethernet
- other:
- qca8k: convert to regmap read/write API, use bulk operations
- rswitch: Improve TX timestamp accuracy
- Intel WiFi (iwlwifi):
- EHT (Wi-Fi 7) rate reporting
- STEP equalizer support: transfer some STEP (connection to radio
on platforms with integrated wifi) related parameters from the
BIOS to the firmware.
- Qualcomm 802.11ax WiFi (ath11k):
- IPQ5018 support
- Fine Timing Measurement (FTM) responder role support
- channel 177 support
- MediaTek WiFi (mt76):
- per-PHY LED support
- mt7996: EHT (Wi-Fi 7) support
- Wireless Ethernet Dispatch (WED) reset support
- switch to using page pool allocator
- RealTek WiFi (rtw89):
- support new version of Bluetooth co-existance
- Mobile:
- rmnet: support TX aggregation"
* tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits)
page_pool: add a comment explaining the fragment counter usage
net: ethtool: fix __ethtool_dev_mm_supported() implementation
ethtool: pse-pd: Fix double word in comments
xsk: add linux/vmalloc.h to xsk.c
sefltests: netdevsim: wait for devlink instance after netns removal
selftest: fib_tests: Always cleanup before exit
net/mlx5e: Align IPsec ASO result memory to be as required by hardware
net/mlx5e: TC, Set CT miss to the specific ct action instance
net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG
net/mlx5: Refactor tc miss handling to a single function
net/mlx5: Kconfig: Make tc offload depend on tc skb extension
net/sched: flower: Support hardware miss to tc action
net/sched: flower: Move filter handle initialization earlier
net/sched: cls_api: Support hardware miss to tc action
net/sched: Rename user cookie and act cookie
sfc: fix builds without CONFIG_RTC_LIB
sfc: clean up some inconsistent indentings
net/mlx4_en: Introduce flexible array to silence overflow warning
net: lan966x: Fix possible deadlock inside PTP
net/ulp: Remove redundant ->clone() test in inet_clone_ulp().
...
Diffstat (limited to 'drivers/rapidio/switches')
-rw-r--r-- | drivers/rapidio/switches/Kconfig | 20 | ||||
-rw-r--r-- | drivers/rapidio/switches/Makefile | 8 | ||||
-rw-r--r-- | drivers/rapidio/switches/idt_gen2.c | 490 | ||||
-rw-r--r-- | drivers/rapidio/switches/idt_gen3.c | 378 | ||||
-rw-r--r-- | drivers/rapidio/switches/idtcps.c | 199 |
5 files changed, 1095 insertions, 0 deletions
diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig new file mode 100644 index 000000000..02771ba3e --- /dev/null +++ b/drivers/rapidio/switches/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# RapidIO switches configuration +# +config RAPIDIO_CPS_XX + tristate "IDT CPS-xx SRIO switches support" + help + Includes support for IDT CPS-16/12/10/8 serial RapidIO switches. + +config RAPIDIO_CPS_GEN2 + tristate "IDT CPS Gen.2 SRIO switch support" + default n + help + Includes support for ITD CPS Gen.2 serial RapidIO switches. + +config RAPIDIO_RXS_GEN3 + tristate "IDT RXS Gen.3 SRIO switch support" + default n + help + Includes support for ITD RXS Gen.3 serial RapidIO switches. diff --git a/drivers/rapidio/switches/Makefile b/drivers/rapidio/switches/Makefile new file mode 100644 index 000000000..ef1749a79 --- /dev/null +++ b/drivers/rapidio/switches/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for RIO switches +# + +obj-$(CONFIG_RAPIDIO_CPS_XX) += idtcps.o +obj-$(CONFIG_RAPIDIO_CPS_GEN2) += idt_gen2.o +obj-$(CONFIG_RAPIDIO_RXS_GEN3) += idt_gen3.o diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c new file mode 100644 index 000000000..8a89bba17 --- /dev/null +++ b/drivers/rapidio/switches/idt_gen2.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * IDT CPS Gen.2 Serial RapidIO switch family support + * + * Copyright 2010 Integrated Device Technology, Inc. + * Alexandre Bounine <alexandre.bounine@idt.com> + */ + +#include <linux/stat.h> +#include <linux/module.h> +#include <linux/rio.h> +#include <linux/rio_drv.h> +#include <linux/rio_ids.h> +#include <linux/delay.h> + +#include <asm/page.h> +#include "../rio.h" + +#define LOCAL_RTE_CONF_DESTID_SEL 0x010070 +#define LOCAL_RTE_CONF_DESTID_SEL_PSEL 0x0000001f + +#define IDT_LT_ERR_REPORT_EN 0x03100c + +#define IDT_PORT_ERR_REPORT_EN(n) (0x031044 + (n)*0x40) +#define IDT_PORT_ERR_REPORT_EN_BC 0x03ff04 + +#define IDT_PORT_ISERR_REPORT_EN(n) (0x03104C + (n)*0x40) +#define IDT_PORT_ISERR_REPORT_EN_BC 0x03ff0c +#define IDT_PORT_INIT_TX_ACQUIRED 0x00000020 + +#define IDT_LANE_ERR_REPORT_EN(n) (0x038010 + (n)*0x100) +#define IDT_LANE_ERR_REPORT_EN_BC 0x03ff10 + +#define IDT_DEV_CTRL_1 0xf2000c +#define IDT_DEV_CTRL_1_GENPW 0x02000000 +#define IDT_DEV_CTRL_1_PRSTBEH 0x00000001 + +#define IDT_CFGBLK_ERR_CAPTURE_EN 0x020008 +#define IDT_CFGBLK_ERR_REPORT 0xf20014 +#define IDT_CFGBLK_ERR_REPORT_GENPW 0x00000002 + +#define IDT_AUX_PORT_ERR_CAP_EN 0x020000 +#define IDT_AUX_ERR_REPORT_EN 0xf20018 +#define IDT_AUX_PORT_ERR_LOG_I2C 0x00000002 +#define IDT_AUX_PORT_ERR_LOG_JTAG 0x00000001 + +#define IDT_ISLTL_ADDRESS_CAP 0x021014 + +#define IDT_RIO_DOMAIN 0xf20020 +#define IDT_RIO_DOMAIN_MASK 0x000000ff + +#define IDT_PW_INFO_CSR 0xf20024 + +#define IDT_SOFT_RESET 0xf20040 +#define IDT_SOFT_RESET_REQ 0x00030097 + +#define IDT_I2C_MCTRL 0xf20050 +#define IDT_I2C_MCTRL_GENPW 0x04000000 + +#define IDT_JTAG_CTRL 0xf2005c +#define IDT_JTAG_CTRL_GENPW 0x00000002 + +#define IDT_LANE_CTRL(n) (0xff8000 + (n)*0x100) +#define IDT_LANE_CTRL_BC 0xffff00 +#define IDT_LANE_CTRL_GENPW 0x00200000 +#define IDT_LANE_DFE_1_BC 0xffff18 +#define IDT_LANE_DFE_2_BC 0xffff1c + +#define IDT_PORT_OPS(n) (0xf40004 + (n)*0x100) +#define IDT_PORT_OPS_GENPW 0x08000000 +#define IDT_PORT_OPS_PL_ELOG 0x00000040 +#define IDT_PORT_OPS_LL_ELOG 0x00000020 +#define IDT_PORT_OPS_LT_ELOG 0x00000010 +#define IDT_PORT_OPS_BC 0xf4ff04 + +#define IDT_PORT_ISERR_DET(n) (0xf40008 + (n)*0x100) + +#define IDT_ERR_CAP 0xfd0000 +#define IDT_ERR_CAP_LOG_OVERWR 0x00000004 + +#define IDT_ERR_RD 0xfd0004 + +#define IDT_DEFAULT_ROUTE 0xde +#define IDT_NO_ROUTE 0xdf + +static int +idtg2_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 route_port) +{ + /* + * Select routing table to update + */ + if (table == RIO_GLOBAL_TABLE) + table = 0; + else + table++; + + if (route_port == RIO_INVALID_ROUTE) + route_port = IDT_DEFAULT_ROUTE; + + rio_mport_write_config_32(mport, destid, hopcount, + LOCAL_RTE_CONF_DESTID_SEL, table); + + /* + * Program destination port for the specified destID + */ + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_DESTID_SEL_CSR, + (u32)route_destid); + + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_PORT_SEL_CSR, + (u32)route_port); + udelay(10); + + return 0; +} + +static int +idtg2_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 *route_port) +{ + u32 result; + + /* + * Select routing table to read + */ + if (table == RIO_GLOBAL_TABLE) + table = 0; + else + table++; + + rio_mport_write_config_32(mport, destid, hopcount, + LOCAL_RTE_CONF_DESTID_SEL, table); + + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_DESTID_SEL_CSR, + route_destid); + + rio_mport_read_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); + + if (IDT_DEFAULT_ROUTE == (u8)result || IDT_NO_ROUTE == (u8)result) + *route_port = RIO_INVALID_ROUTE; + else + *route_port = (u8)result; + + return 0; +} + +static int +idtg2_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table) +{ + u32 i; + + /* + * Select routing table to read + */ + if (table == RIO_GLOBAL_TABLE) + table = 0; + else + table++; + + rio_mport_write_config_32(mport, destid, hopcount, + LOCAL_RTE_CONF_DESTID_SEL, table); + + for (i = RIO_STD_RTE_CONF_EXTCFGEN; + i <= (RIO_STD_RTE_CONF_EXTCFGEN | 0xff);) { + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_DESTID_SEL_CSR, i); + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_PORT_SEL_CSR, + (IDT_DEFAULT_ROUTE << 24) | (IDT_DEFAULT_ROUTE << 16) | + (IDT_DEFAULT_ROUTE << 8) | IDT_DEFAULT_ROUTE); + i += 4; + } + + return 0; +} + + +static int +idtg2_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount, + u8 sw_domain) +{ + /* + * Switch domain configuration operates only at global level + */ + rio_mport_write_config_32(mport, destid, hopcount, + IDT_RIO_DOMAIN, (u32)sw_domain); + return 0; +} + +static int +idtg2_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, + u8 *sw_domain) +{ + u32 regval; + + /* + * Switch domain configuration operates only at global level + */ + rio_mport_read_config_32(mport, destid, hopcount, + IDT_RIO_DOMAIN, ®val); + + *sw_domain = (u8)(regval & 0xff); + + return 0; +} + +static int +idtg2_em_init(struct rio_dev *rdev) +{ + u32 regval; + int i, tmp; + + /* + * This routine performs device-specific initialization only. + * All standard EM configuration should be performed at upper level. + */ + + pr_debug("RIO: %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); + + /* Set Port-Write info CSR: PRIO=3 and CRF=1 */ + rio_write_config_32(rdev, IDT_PW_INFO_CSR, 0x0000e000); + + /* + * Configure LT LAYER error reporting. + */ + + /* Enable standard (RIO.p8) error reporting */ + rio_write_config_32(rdev, IDT_LT_ERR_REPORT_EN, + REM_LTL_ERR_ILLTRAN | REM_LTL_ERR_UNSOLR | + REM_LTL_ERR_UNSUPTR); + + /* Use Port-Writes for LT layer error reporting. + * Enable per-port reset + */ + rio_read_config_32(rdev, IDT_DEV_CTRL_1, ®val); + rio_write_config_32(rdev, IDT_DEV_CTRL_1, + regval | IDT_DEV_CTRL_1_GENPW | IDT_DEV_CTRL_1_PRSTBEH); + + /* + * Configure PORT error reporting. + */ + + /* Report all RIO.p8 errors supported by device */ + rio_write_config_32(rdev, IDT_PORT_ERR_REPORT_EN_BC, 0x807e8037); + + /* Configure reporting of implementation specific errors/events */ + rio_write_config_32(rdev, IDT_PORT_ISERR_REPORT_EN_BC, + IDT_PORT_INIT_TX_ACQUIRED); + + /* Use Port-Writes for port error reporting and enable error logging */ + tmp = RIO_GET_TOTAL_PORTS(rdev->swpinfo); + for (i = 0; i < tmp; i++) { + rio_read_config_32(rdev, IDT_PORT_OPS(i), ®val); + rio_write_config_32(rdev, + IDT_PORT_OPS(i), regval | IDT_PORT_OPS_GENPW | + IDT_PORT_OPS_PL_ELOG | + IDT_PORT_OPS_LL_ELOG | + IDT_PORT_OPS_LT_ELOG); + } + /* Overwrite error log if full */ + rio_write_config_32(rdev, IDT_ERR_CAP, IDT_ERR_CAP_LOG_OVERWR); + + /* + * Configure LANE error reporting. + */ + + /* Disable line error reporting */ + rio_write_config_32(rdev, IDT_LANE_ERR_REPORT_EN_BC, 0); + + /* Use Port-Writes for lane error reporting (when enabled) + * (do per-lane update because lanes may have different configuration) + */ + tmp = (rdev->did == RIO_DID_IDTCPS1848) ? 48 : 16; + for (i = 0; i < tmp; i++) { + rio_read_config_32(rdev, IDT_LANE_CTRL(i), ®val); + rio_write_config_32(rdev, IDT_LANE_CTRL(i), + regval | IDT_LANE_CTRL_GENPW); + } + + /* + * Configure AUX error reporting. + */ + + /* Disable JTAG and I2C Error capture */ + rio_write_config_32(rdev, IDT_AUX_PORT_ERR_CAP_EN, 0); + + /* Disable JTAG and I2C Error reporting/logging */ + rio_write_config_32(rdev, IDT_AUX_ERR_REPORT_EN, 0); + + /* Disable Port-Write notification from JTAG */ + rio_write_config_32(rdev, IDT_JTAG_CTRL, 0); + + /* Disable Port-Write notification from I2C */ + rio_read_config_32(rdev, IDT_I2C_MCTRL, ®val); + rio_write_config_32(rdev, IDT_I2C_MCTRL, regval & ~IDT_I2C_MCTRL_GENPW); + + /* + * Configure CFG_BLK error reporting. + */ + + /* Disable Configuration Block error capture */ + rio_write_config_32(rdev, IDT_CFGBLK_ERR_CAPTURE_EN, 0); + + /* Disable Port-Writes for Configuration Block error reporting */ + rio_read_config_32(rdev, IDT_CFGBLK_ERR_REPORT, ®val); + rio_write_config_32(rdev, IDT_CFGBLK_ERR_REPORT, + regval & ~IDT_CFGBLK_ERR_REPORT_GENPW); + + /* set TVAL = ~50us */ + rio_write_config_32(rdev, + rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); + + return 0; +} + +static int +idtg2_em_handler(struct rio_dev *rdev, u8 portnum) +{ + u32 regval, em_perrdet, em_ltlerrdet; + + rio_read_config_32(rdev, + rdev->em_efptr + RIO_EM_LTL_ERR_DETECT, &em_ltlerrdet); + if (em_ltlerrdet) { + /* Service Logical/Transport Layer Error(s) */ + if (em_ltlerrdet & REM_LTL_ERR_IMPSPEC) { + /* Implementation specific error reported */ + rio_read_config_32(rdev, + IDT_ISLTL_ADDRESS_CAP, ®val); + + pr_debug("RIO: %s Implementation Specific LTL errors" \ + " 0x%x @(0x%x)\n", + rio_name(rdev), em_ltlerrdet, regval); + + /* Clear implementation specific address capture CSR */ + rio_write_config_32(rdev, IDT_ISLTL_ADDRESS_CAP, 0); + + } + } + + rio_read_config_32(rdev, + rdev->em_efptr + RIO_EM_PN_ERR_DETECT(portnum), &em_perrdet); + if (em_perrdet) { + /* Service Port-Level Error(s) */ + if (em_perrdet & REM_PED_IMPL_SPEC) { + /* Implementation Specific port error reported */ + + /* Get IS errors reported */ + rio_read_config_32(rdev, + IDT_PORT_ISERR_DET(portnum), ®val); + + pr_debug("RIO: %s Implementation Specific Port" \ + " errors 0x%x\n", rio_name(rdev), regval); + + /* Clear all implementation specific events */ + rio_write_config_32(rdev, + IDT_PORT_ISERR_DET(portnum), 0); + } + } + + return 0; +} + +static ssize_t +idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct rio_dev *rdev = to_rio_dev(dev); + ssize_t len = 0; + u32 regval; + + while (!rio_read_config_32(rdev, IDT_ERR_RD, ®val)) { + if (!regval) /* 0 = end of log */ + break; + len += snprintf(buf + len, PAGE_SIZE - len, + "%08x\n", regval); + if (len >= (PAGE_SIZE - 10)) + break; + } + + return len; +} + +static DEVICE_ATTR(errlog, S_IRUGO, idtg2_show_errlog, NULL); + +static int idtg2_sysfs(struct rio_dev *rdev, bool create) +{ + struct device *dev = &rdev->dev; + int err = 0; + + if (create) { + /* Initialize sysfs entries */ + err = device_create_file(dev, &dev_attr_errlog); + if (err) + dev_err(dev, "Unable create sysfs errlog file\n"); + } else + device_remove_file(dev, &dev_attr_errlog); + + return err; +} + +static struct rio_switch_ops idtg2_switch_ops = { + .owner = THIS_MODULE, + .add_entry = idtg2_route_add_entry, + .get_entry = idtg2_route_get_entry, + .clr_table = idtg2_route_clr_table, + .set_domain = idtg2_set_domain, + .get_domain = idtg2_get_domain, + .em_init = idtg2_em_init, + .em_handle = idtg2_em_handler, +}; + +static int idtg2_probe(struct rio_dev *rdev, const struct rio_device_id *id) +{ + pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); + + spin_lock(&rdev->rswitch->lock); + + if (rdev->rswitch->ops) { + spin_unlock(&rdev->rswitch->lock); + return -EINVAL; + } + + rdev->rswitch->ops = &idtg2_switch_ops; + + if (rdev->do_enum) { + /* Ensure that default routing is disabled on startup */ + rio_write_config_32(rdev, + RIO_STD_RTE_DEFAULT_PORT, IDT_NO_ROUTE); + } + + spin_unlock(&rdev->rswitch->lock); + + /* Create device-specific sysfs attributes */ + idtg2_sysfs(rdev, true); + + return 0; +} + +static void idtg2_remove(struct rio_dev *rdev) +{ + pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); + spin_lock(&rdev->rswitch->lock); + if (rdev->rswitch->ops != &idtg2_switch_ops) { + spin_unlock(&rdev->rswitch->lock); + return; + } + rdev->rswitch->ops = NULL; + spin_unlock(&rdev->rswitch->lock); + /* Remove device-specific sysfs attributes */ + idtg2_sysfs(rdev, false); +} + +static const struct rio_device_id idtg2_id_table[] = { + {RIO_DEVICE(RIO_DID_IDTCPS1848, RIO_VID_IDT)}, + {RIO_DEVICE(RIO_DID_IDTCPS1616, RIO_VID_IDT)}, + {RIO_DEVICE(RIO_DID_IDTVPS1616, RIO_VID_IDT)}, + {RIO_DEVICE(RIO_DID_IDTSPS1616, RIO_VID_IDT)}, + {RIO_DEVICE(RIO_DID_IDTCPS1432, RIO_VID_IDT)}, + { 0, } /* terminate list */ +}; + +static struct rio_driver idtg2_driver = { + .name = "idt_gen2", + .id_table = idtg2_id_table, + .probe = idtg2_probe, + .remove = idtg2_remove, +}; + +static int __init idtg2_init(void) +{ + return rio_register_driver(&idtg2_driver); +} + +static void __exit idtg2_exit(void) +{ + pr_debug("RIO: %s\n", __func__); + rio_unregister_driver(&idtg2_driver); + pr_debug("RIO: %s done\n", __func__); +} + +device_initcall(idtg2_init); +module_exit(idtg2_exit); + +MODULE_DESCRIPTION("IDT CPS Gen.2 Serial RapidIO switch family driver"); +MODULE_AUTHOR("Integrated Device Technology, Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/rapidio/switches/idt_gen3.c b/drivers/rapidio/switches/idt_gen3.c new file mode 100644 index 000000000..d7537e621 --- /dev/null +++ b/drivers/rapidio/switches/idt_gen3.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * IDT RXS Gen.3 Serial RapidIO switch family support + * + * Copyright 2016 Integrated Device Technology, Inc. + */ + +#include <linux/stat.h> +#include <linux/module.h> +#include <linux/rio.h> +#include <linux/rio_drv.h> +#include <linux/rio_ids.h> +#include <linux/delay.h> + +#include <asm/page.h> +#include "../rio.h" + +#define RIO_EM_PW_STAT 0x40020 +#define RIO_PW_CTL 0x40204 +#define RIO_PW_CTL_PW_TMR 0xffffff00 +#define RIO_PW_ROUTE 0x40208 + +#define RIO_EM_DEV_INT_EN 0x40030 + +#define RIO_PLM_SPx_IMP_SPEC_CTL(x) (0x10100 + (x)*0x100) +#define RIO_PLM_SPx_IMP_SPEC_CTL_SOFT_RST 0x02000000 + +#define RIO_PLM_SPx_PW_EN(x) (0x10118 + (x)*0x100) +#define RIO_PLM_SPx_PW_EN_OK2U 0x40000000 +#define RIO_PLM_SPx_PW_EN_LINIT 0x10000000 + +#define RIO_BC_L2_Gn_ENTRYx_CSR(n, x) (0x31000 + (n)*0x400 + (x)*0x4) +#define RIO_SPx_L2_Gn_ENTRYy_CSR(x, n, y) \ + (0x51000 + (x)*0x2000 + (n)*0x400 + (y)*0x4) + +static int +idtg3_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 route_port) +{ + u32 rval; + u32 entry = route_port; + int err = 0; + + pr_debug("RIO: %s t=0x%x did_%x to p_%x\n", + __func__, table, route_destid, entry); + + if (route_destid > 0xFF) + return -EINVAL; + + if (route_port == RIO_INVALID_ROUTE) + entry = RIO_RT_ENTRY_DROP_PKT; + + if (table == RIO_GLOBAL_TABLE) { + /* Use broadcast register to update all per-port tables */ + err = rio_mport_write_config_32(mport, destid, hopcount, + RIO_BC_L2_Gn_ENTRYx_CSR(0, route_destid), + entry); + return err; + } + + /* + * Verify that specified port/table number is valid + */ + err = rio_mport_read_config_32(mport, destid, hopcount, + RIO_SWP_INFO_CAR, &rval); + if (err) + return err; + + if (table >= RIO_GET_TOTAL_PORTS(rval)) + return -EINVAL; + + err = rio_mport_write_config_32(mport, destid, hopcount, + RIO_SPx_L2_Gn_ENTRYy_CSR(table, 0, route_destid), + entry); + return err; +} + +static int +idtg3_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 *route_port) +{ + u32 rval; + int err; + + if (route_destid > 0xFF) + return -EINVAL; + + err = rio_mport_read_config_32(mport, destid, hopcount, + RIO_SWP_INFO_CAR, &rval); + if (err) + return err; + + /* + * This switch device does not have the dedicated global routing table. + * It is substituted by reading routing table of the ingress port of + * maintenance read requests. + */ + if (table == RIO_GLOBAL_TABLE) + table = RIO_GET_PORT_NUM(rval); + else if (table >= RIO_GET_TOTAL_PORTS(rval)) + return -EINVAL; + + err = rio_mport_read_config_32(mport, destid, hopcount, + RIO_SPx_L2_Gn_ENTRYy_CSR(table, 0, route_destid), + &rval); + if (err) + return err; + + if (rval == RIO_RT_ENTRY_DROP_PKT) + *route_port = RIO_INVALID_ROUTE; + else + *route_port = (u8)rval; + + return 0; +} + +static int +idtg3_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table) +{ + u32 i; + u32 rval; + int err; + + if (table == RIO_GLOBAL_TABLE) { + for (i = 0; i <= 0xff; i++) { + err = rio_mport_write_config_32(mport, destid, hopcount, + RIO_BC_L2_Gn_ENTRYx_CSR(0, i), + RIO_RT_ENTRY_DROP_PKT); + if (err) + break; + } + + return err; + } + + err = rio_mport_read_config_32(mport, destid, hopcount, + RIO_SWP_INFO_CAR, &rval); + if (err) + return err; + + if (table >= RIO_GET_TOTAL_PORTS(rval)) + return -EINVAL; + + for (i = 0; i <= 0xff; i++) { + err = rio_mport_write_config_32(mport, destid, hopcount, + RIO_SPx_L2_Gn_ENTRYy_CSR(table, 0, i), + RIO_RT_ENTRY_DROP_PKT); + if (err) + break; + } + + return err; +} + +/* + * This routine performs device-specific initialization only. + * All standard EM configuration should be performed at upper level. + */ +static int +idtg3_em_init(struct rio_dev *rdev) +{ + int i, tmp; + u32 rval; + + pr_debug("RIO: %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount); + + /* Disable assertion of interrupt signal */ + rio_write_config_32(rdev, RIO_EM_DEV_INT_EN, 0); + + /* Disable port-write event notifications during initialization */ + rio_write_config_32(rdev, rdev->em_efptr + RIO_EM_PW_TX_CTRL, + RIO_EM_PW_TX_CTRL_PW_DIS); + + /* Configure Port-Write notifications for hot-swap events */ + tmp = RIO_GET_TOTAL_PORTS(rdev->swpinfo); + for (i = 0; i < tmp; i++) { + + rio_read_config_32(rdev, + RIO_DEV_PORT_N_ERR_STS_CSR(rdev, i), + &rval); + if (rval & RIO_PORT_N_ERR_STS_PORT_UA) + continue; + + /* Clear events signaled before enabling notification */ + rio_write_config_32(rdev, + rdev->em_efptr + RIO_EM_PN_ERR_DETECT(i), 0); + + /* Enable event notifications */ + rio_write_config_32(rdev, + rdev->em_efptr + RIO_EM_PN_ERRRATE_EN(i), + RIO_EM_PN_ERRRATE_EN_OK2U | RIO_EM_PN_ERRRATE_EN_U2OK); + /* Enable port-write generation on events */ + rio_write_config_32(rdev, RIO_PLM_SPx_PW_EN(i), + RIO_PLM_SPx_PW_EN_OK2U | RIO_PLM_SPx_PW_EN_LINIT); + + } + + /* Set Port-Write destination port */ + tmp = RIO_GET_PORT_NUM(rdev->swpinfo); + rio_write_config_32(rdev, RIO_PW_ROUTE, 1 << tmp); + + + /* Enable sending port-write event notifications */ + rio_write_config_32(rdev, rdev->em_efptr + RIO_EM_PW_TX_CTRL, 0); + + /* set TVAL = ~50us */ + rio_write_config_32(rdev, + rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); + return 0; +} + + +/* + * idtg3_em_handler - device-specific error handler + * + * If the link is down (PORT_UNINIT) does nothing - this is considered + * as link partner removal from the port. + * + * If the link is up (PORT_OK) - situation is handled as *new* device insertion. + * In this case ERR_STOP bits are cleared by issuing soft reset command to the + * reporting port. Inbound and outbound ackIDs are cleared by the reset as well. + * This way the port is synchronized with freshly inserted device (assuming it + * was reset/powered-up on insertion). + * + * TODO: This is not sufficient in a situation when a link between two devices + * was down and up again (e.g. cable disconnect). For that situation full ackID + * realignment process has to be implemented. + */ +static int +idtg3_em_handler(struct rio_dev *rdev, u8 pnum) +{ + u32 err_status; + u32 rval; + + rio_read_config_32(rdev, + RIO_DEV_PORT_N_ERR_STS_CSR(rdev, pnum), + &err_status); + + /* Do nothing for device/link removal */ + if (err_status & RIO_PORT_N_ERR_STS_PORT_UNINIT) + return 0; + + /* When link is OK we have a device insertion. + * Request port soft reset to clear errors if they present. + * Inbound and outbound ackIDs will be 0 after reset. + */ + if (err_status & (RIO_PORT_N_ERR_STS_OUT_ES | + RIO_PORT_N_ERR_STS_INP_ES)) { + rio_read_config_32(rdev, RIO_PLM_SPx_IMP_SPEC_CTL(pnum), &rval); + rio_write_config_32(rdev, RIO_PLM_SPx_IMP_SPEC_CTL(pnum), + rval | RIO_PLM_SPx_IMP_SPEC_CTL_SOFT_RST); + udelay(10); + rio_write_config_32(rdev, RIO_PLM_SPx_IMP_SPEC_CTL(pnum), rval); + msleep(500); + } + + return 0; +} + +static struct rio_switch_ops idtg3_switch_ops = { + .owner = THIS_MODULE, + .add_entry = idtg3_route_add_entry, + .get_entry = idtg3_route_get_entry, + .clr_table = idtg3_route_clr_table, + .em_init = idtg3_em_init, + .em_handle = idtg3_em_handler, +}; + +static int idtg3_probe(struct rio_dev *rdev, const struct rio_device_id *id) +{ + pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); + + spin_lock(&rdev->rswitch->lock); + + if (rdev->rswitch->ops) { + spin_unlock(&rdev->rswitch->lock); + return -EINVAL; + } + + rdev->rswitch->ops = &idtg3_switch_ops; + + if (rdev->do_enum) { + /* Disable hierarchical routing support: Existing fabric + * enumeration/discovery process (see rio-scan.c) uses 8-bit + * flat destination ID routing only. + */ + rio_write_config_32(rdev, 0x5000 + RIO_BC_RT_CTL_CSR, 0); + } + + spin_unlock(&rdev->rswitch->lock); + + return 0; +} + +static void idtg3_remove(struct rio_dev *rdev) +{ + pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); + spin_lock(&rdev->rswitch->lock); + if (rdev->rswitch->ops == &idtg3_switch_ops) + rdev->rswitch->ops = NULL; + spin_unlock(&rdev->rswitch->lock); +} + +/* + * Gen3 switches repeat sending PW messages until a corresponding event flag + * is cleared. Use shutdown notification to disable generation of port-write + * messages if their destination node is shut down. + */ +static void idtg3_shutdown(struct rio_dev *rdev) +{ + int i; + u32 rval; + u16 destid; + + /* Currently the enumerator node acts also as PW handler */ + if (!rdev->do_enum) + return; + + pr_debug("RIO: %s(%s)\n", __func__, rio_name(rdev)); + + rio_read_config_32(rdev, RIO_PW_ROUTE, &rval); + i = RIO_GET_PORT_NUM(rdev->swpinfo); + + /* Check port-write destination port */ + if (!((1 << i) & rval)) + return; + + /* Disable sending port-write event notifications if PW destID + * matches to one of the enumerator node + */ + rio_read_config_32(rdev, rdev->em_efptr + RIO_EM_PW_TGT_DEVID, &rval); + + if (rval & RIO_EM_PW_TGT_DEVID_DEV16) + destid = rval >> 16; + else + destid = ((rval & RIO_EM_PW_TGT_DEVID_D8) >> 16); + + if (rdev->net->hport->host_deviceid == destid) { + rio_write_config_32(rdev, + rdev->em_efptr + RIO_EM_PW_TX_CTRL, 0); + pr_debug("RIO: %s(%s) PW transmission disabled\n", + __func__, rio_name(rdev)); + } +} + +static const struct rio_device_id idtg3_id_table[] = { + {RIO_DEVICE(RIO_DID_IDTRXS1632, RIO_VID_IDT)}, + {RIO_DEVICE(RIO_DID_IDTRXS2448, RIO_VID_IDT)}, + { 0, } /* terminate list */ +}; + +static struct rio_driver idtg3_driver = { + .name = "idt_gen3", + .id_table = idtg3_id_table, + .probe = idtg3_probe, + .remove = idtg3_remove, + .shutdown = idtg3_shutdown, +}; + +static int __init idtg3_init(void) +{ + return rio_register_driver(&idtg3_driver); +} + +static void __exit idtg3_exit(void) +{ + pr_debug("RIO: %s\n", __func__); + rio_unregister_driver(&idtg3_driver); + pr_debug("RIO: %s done\n", __func__); +} + +device_initcall(idtg3_init); +module_exit(idtg3_exit); + +MODULE_DESCRIPTION("IDT RXS Gen.3 Serial RapidIO switch family driver"); +MODULE_AUTHOR("Integrated Device Technology, Inc."); +MODULE_LICENSE("GPL"); diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c new file mode 100644 index 000000000..c825728eb --- /dev/null +++ b/drivers/rapidio/switches/idtcps.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * IDT CPS RapidIO switches support + * + * Copyright 2009-2010 Integrated Device Technology, Inc. + * Alexandre Bounine <alexandre.bounine@idt.com> + */ + +#include <linux/rio.h> +#include <linux/rio_drv.h> +#include <linux/rio_ids.h> +#include <linux/module.h> +#include "../rio.h" + +#define CPS_DEFAULT_ROUTE 0xde +#define CPS_NO_ROUTE 0xdf + +#define IDTCPS_RIO_DOMAIN 0xf20020 + +static int +idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 route_port) +{ + u32 result; + + if (route_port == RIO_INVALID_ROUTE) + route_port = CPS_DEFAULT_ROUTE; + + if (table == RIO_GLOBAL_TABLE) { + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); + + rio_mport_read_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); + + result = (0xffffff00 & result) | (u32)route_port; + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_PORT_SEL_CSR, result); + } + + return 0; +} + +static int +idtcps_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table, u16 route_destid, u8 *route_port) +{ + u32 result; + + if (table == RIO_GLOBAL_TABLE) { + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid); + + rio_mport_read_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_PORT_SEL_CSR, &result); + + if (CPS_DEFAULT_ROUTE == (u8)result || + CPS_NO_ROUTE == (u8)result) + *route_port = RIO_INVALID_ROUTE; + else + *route_port = (u8)result; + } + + return 0; +} + +static int +idtcps_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, + u16 table) +{ + u32 i; + + if (table == RIO_GLOBAL_TABLE) { + for (i = 0x80000000; i <= 0x800000ff;) { + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_DESTID_SEL_CSR, i); + rio_mport_write_config_32(mport, destid, hopcount, + RIO_STD_RTE_CONF_PORT_SEL_CSR, + (CPS_DEFAULT_ROUTE << 24) | + (CPS_DEFAULT_ROUTE << 16) | + (CPS_DEFAULT_ROUTE << 8) | CPS_DEFAULT_ROUTE); + i += 4; + } + } + + return 0; +} + +static int +idtcps_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount, + u8 sw_domain) +{ + /* + * Switch domain configuration operates only at global level + */ + rio_mport_write_config_32(mport, destid, hopcount, + IDTCPS_RIO_DOMAIN, (u32)sw_domain); + return 0; +} + +static int +idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount, + u8 *sw_domain) +{ + u32 regval; + + /* + * Switch domain configuration operates only at global level + */ + rio_mport_read_config_32(mport, destid, hopcount, + IDTCPS_RIO_DOMAIN, ®val); + + *sw_domain = (u8)(regval & 0xff); + + return 0; +} + +static struct rio_switch_ops idtcps_switch_ops = { + .owner = THIS_MODULE, + .add_entry = idtcps_route_add_entry, + .get_entry = idtcps_route_get_entry, + .clr_table = idtcps_route_clr_table, + .set_domain = idtcps_set_domain, + .get_domain = idtcps_get_domain, + .em_init = NULL, + .em_handle = NULL, +}; + +static int idtcps_probe(struct rio_dev *rdev, const struct rio_device_id *id) +{ + pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); + + spin_lock(&rdev->rswitch->lock); + + if (rdev->rswitch->ops) { + spin_unlock(&rdev->rswitch->lock); + return -EINVAL; + } + + rdev->rswitch->ops = &idtcps_switch_ops; + + if (rdev->do_enum) { + /* set TVAL = ~50us */ + rio_write_config_32(rdev, + rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8); + /* Ensure that default routing is disabled on startup */ + rio_write_config_32(rdev, + RIO_STD_RTE_DEFAULT_PORT, CPS_NO_ROUTE); + } + + spin_unlock(&rdev->rswitch->lock); + return 0; +} + +static void idtcps_remove(struct rio_dev *rdev) +{ + pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); + spin_lock(&rdev->rswitch->lock); + if (rdev->rswitch->ops != &idtcps_switch_ops) { + spin_unlock(&rdev->rswitch->lock); + return; + } + rdev->rswitch->ops = NULL; + spin_unlock(&rdev->rswitch->lock); +} + +static const struct rio_device_id idtcps_id_table[] = { + {RIO_DEVICE(RIO_DID_IDTCPS6Q, RIO_VID_IDT)}, + {RIO_DEVICE(RIO_DID_IDTCPS8, RIO_VID_IDT)}, + {RIO_DEVICE(RIO_DID_IDTCPS10Q, RIO_VID_IDT)}, + {RIO_DEVICE(RIO_DID_IDTCPS12, RIO_VID_IDT)}, + {RIO_DEVICE(RIO_DID_IDTCPS16, RIO_VID_IDT)}, + {RIO_DEVICE(RIO_DID_IDT70K200, RIO_VID_IDT)}, + { 0, } /* terminate list */ +}; + +static struct rio_driver idtcps_driver = { + .name = "idtcps", + .id_table = idtcps_id_table, + .probe = idtcps_probe, + .remove = idtcps_remove, +}; + +static int __init idtcps_init(void) +{ + return rio_register_driver(&idtcps_driver); +} + +static void __exit idtcps_exit(void) +{ + rio_unregister_driver(&idtcps_driver); +} + +device_initcall(idtcps_init); +module_exit(idtcps_exit); + +MODULE_DESCRIPTION("IDT CPS Gen.1 Serial RapidIO switch family driver"); +MODULE_AUTHOR("Integrated Device Technology, Inc."); +MODULE_LICENSE("GPL"); |