18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * rionet - Ethernet driver over RapidIO messaging services 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2005 MontaVista Software, Inc. 68c2ecf20Sopenharmony_ci * Matt Porter <mporter@kernel.crashing.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/rio.h> 148c2ecf20Sopenharmony_ci#include <linux/rio_drv.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/rio_ids.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 198c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 208c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 218c2ecf20Sopenharmony_ci#include <linux/crc32.h> 228c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 238c2ecf20Sopenharmony_ci#include <linux/reboot.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define DRV_NAME "rionet" 268c2ecf20Sopenharmony_ci#define DRV_VERSION "0.3" 278c2ecf20Sopenharmony_ci#define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>" 288c2ecf20Sopenharmony_ci#define DRV_DESC "Ethernet over RapidIO" 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRV_AUTHOR); 318c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_DESC); 328c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define RIONET_DEFAULT_MSGLEVEL \ 358c2ecf20Sopenharmony_ci (NETIF_MSG_DRV | \ 368c2ecf20Sopenharmony_ci NETIF_MSG_LINK | \ 378c2ecf20Sopenharmony_ci NETIF_MSG_RX_ERR | \ 388c2ecf20Sopenharmony_ci NETIF_MSG_TX_ERR) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define RIONET_DOORBELL_JOIN 0x1000 418c2ecf20Sopenharmony_ci#define RIONET_DOORBELL_LEAVE 0x1001 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define RIONET_MAILBOX 0 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE 468c2ecf20Sopenharmony_ci#define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE 478c2ecf20Sopenharmony_ci#define RIONET_MAX_NETS 8 488c2ecf20Sopenharmony_ci#define RIONET_MSG_SIZE RIO_MAX_MSG_SIZE 498c2ecf20Sopenharmony_ci#define RIONET_MAX_MTU (RIONET_MSG_SIZE - ETH_HLEN) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct rionet_private { 528c2ecf20Sopenharmony_ci struct rio_mport *mport; 538c2ecf20Sopenharmony_ci struct sk_buff *rx_skb[RIONET_RX_RING_SIZE]; 548c2ecf20Sopenharmony_ci struct sk_buff *tx_skb[RIONET_TX_RING_SIZE]; 558c2ecf20Sopenharmony_ci int rx_slot; 568c2ecf20Sopenharmony_ci int tx_slot; 578c2ecf20Sopenharmony_ci int tx_cnt; 588c2ecf20Sopenharmony_ci int ack_slot; 598c2ecf20Sopenharmony_ci spinlock_t lock; 608c2ecf20Sopenharmony_ci spinlock_t tx_lock; 618c2ecf20Sopenharmony_ci u32 msg_enable; 628c2ecf20Sopenharmony_ci bool open; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistruct rionet_peer { 668c2ecf20Sopenharmony_ci struct list_head node; 678c2ecf20Sopenharmony_ci struct rio_dev *rdev; 688c2ecf20Sopenharmony_ci struct resource *res; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct rionet_net { 728c2ecf20Sopenharmony_ci struct net_device *ndev; 738c2ecf20Sopenharmony_ci struct list_head peers; 748c2ecf20Sopenharmony_ci spinlock_t lock; /* net info access lock */ 758c2ecf20Sopenharmony_ci struct rio_dev **active; 768c2ecf20Sopenharmony_ci int nact; /* number of active peers */ 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic struct rionet_net nets[RIONET_MAX_NETS]; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define is_rionet_capable(src_ops, dst_ops) \ 828c2ecf20Sopenharmony_ci ((src_ops & RIO_SRC_OPS_DATA_MSG) && \ 838c2ecf20Sopenharmony_ci (dst_ops & RIO_DST_OPS_DATA_MSG) && \ 848c2ecf20Sopenharmony_ci (src_ops & RIO_SRC_OPS_DOORBELL) && \ 858c2ecf20Sopenharmony_ci (dst_ops & RIO_DST_OPS_DOORBELL)) 868c2ecf20Sopenharmony_ci#define dev_rionet_capable(dev) \ 878c2ecf20Sopenharmony_ci is_rionet_capable(dev->src_ops, dev->dst_ops) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define RIONET_MAC_MATCH(x) (!memcmp((x), "\00\01\00\01", 4)) 908c2ecf20Sopenharmony_ci#define RIONET_GET_DESTID(x) ((*((u8 *)x + 4) << 8) | *((u8 *)x + 5)) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int rionet_rx_clean(struct net_device *ndev) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci int i; 958c2ecf20Sopenharmony_ci int error = 0; 968c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 978c2ecf20Sopenharmony_ci void *data; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci i = rnet->rx_slot; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci do { 1028c2ecf20Sopenharmony_ci if (!rnet->rx_skb[i]) 1038c2ecf20Sopenharmony_ci continue; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (!(data = rio_get_inb_message(rnet->mport, RIONET_MAILBOX))) 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci rnet->rx_skb[i]->data = data; 1098c2ecf20Sopenharmony_ci skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE); 1108c2ecf20Sopenharmony_ci rnet->rx_skb[i]->protocol = 1118c2ecf20Sopenharmony_ci eth_type_trans(rnet->rx_skb[i], ndev); 1128c2ecf20Sopenharmony_ci error = netif_rx(rnet->rx_skb[i]); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (error == NET_RX_DROP) { 1158c2ecf20Sopenharmony_ci ndev->stats.rx_dropped++; 1168c2ecf20Sopenharmony_ci } else { 1178c2ecf20Sopenharmony_ci ndev->stats.rx_packets++; 1188c2ecf20Sopenharmony_ci ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return i; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void rionet_rx_fill(struct net_device *ndev, int end) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci int i; 1298c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci i = rnet->rx_slot; 1328c2ecf20Sopenharmony_ci do { 1338c2ecf20Sopenharmony_ci rnet->rx_skb[i] = dev_alloc_skb(RIO_MAX_MSG_SIZE); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (!rnet->rx_skb[i]) 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci rio_add_inb_buffer(rnet->mport, RIONET_MAILBOX, 1398c2ecf20Sopenharmony_ci rnet->rx_skb[i]->data); 1408c2ecf20Sopenharmony_ci } while ((i = (i + 1) % RIONET_RX_RING_SIZE) != end); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci rnet->rx_slot = i; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, 1468c2ecf20Sopenharmony_ci struct rio_dev *rdev) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len); 1518c2ecf20Sopenharmony_ci rnet->tx_skb[rnet->tx_slot] = skb; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci ndev->stats.tx_packets++; 1548c2ecf20Sopenharmony_ci ndev->stats.tx_bytes += skb->len; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (++rnet->tx_cnt == RIONET_TX_RING_SIZE) 1578c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci ++rnet->tx_slot; 1608c2ecf20Sopenharmony_ci rnet->tx_slot &= (RIONET_TX_RING_SIZE - 1); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (netif_msg_tx_queued(rnet)) 1638c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: queued skb len %8.8x\n", DRV_NAME, 1648c2ecf20Sopenharmony_ci skb->len); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic netdev_tx_t rionet_start_xmit(struct sk_buff *skb, 1708c2ecf20Sopenharmony_ci struct net_device *ndev) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci int i; 1738c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 1748c2ecf20Sopenharmony_ci struct ethhdr *eth = (struct ethhdr *)skb->data; 1758c2ecf20Sopenharmony_ci u16 destid; 1768c2ecf20Sopenharmony_ci unsigned long flags; 1778c2ecf20Sopenharmony_ci int add_num = 1; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci spin_lock_irqsave(&rnet->tx_lock, flags); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(eth->h_dest)) 1828c2ecf20Sopenharmony_ci add_num = nets[rnet->mport->id].nact; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) { 1858c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 1868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rnet->tx_lock, flags); 1878c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", 1888c2ecf20Sopenharmony_ci ndev->name); 1898c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(eth->h_dest)) { 1938c2ecf20Sopenharmony_ci int count = 0; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size); 1968c2ecf20Sopenharmony_ci i++) 1978c2ecf20Sopenharmony_ci if (nets[rnet->mport->id].active[i]) { 1988c2ecf20Sopenharmony_ci rionet_queue_tx_msg(skb, ndev, 1998c2ecf20Sopenharmony_ci nets[rnet->mport->id].active[i]); 2008c2ecf20Sopenharmony_ci if (count) 2018c2ecf20Sopenharmony_ci refcount_inc(&skb->users); 2028c2ecf20Sopenharmony_ci count++; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci } else if (RIONET_MAC_MATCH(eth->h_dest)) { 2058c2ecf20Sopenharmony_ci destid = RIONET_GET_DESTID(eth->h_dest); 2068c2ecf20Sopenharmony_ci if (nets[rnet->mport->id].active[destid]) 2078c2ecf20Sopenharmony_ci rionet_queue_tx_msg(skb, ndev, 2088c2ecf20Sopenharmony_ci nets[rnet->mport->id].active[destid]); 2098c2ecf20Sopenharmony_ci else { 2108c2ecf20Sopenharmony_ci /* 2118c2ecf20Sopenharmony_ci * If the target device was removed from the list of 2128c2ecf20Sopenharmony_ci * active peers but we still have TX packets targeting 2138c2ecf20Sopenharmony_ci * it just report sending a packet to the target 2148c2ecf20Sopenharmony_ci * (without actual packet transfer). 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_ci ndev->stats.tx_packets++; 2178c2ecf20Sopenharmony_ci ndev->stats.tx_bytes += skb->len; 2188c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rnet->tx_lock, flags); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid, 2288c2ecf20Sopenharmony_ci u16 info) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct net_device *ndev = dev_id; 2318c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 2328c2ecf20Sopenharmony_ci struct rionet_peer *peer; 2338c2ecf20Sopenharmony_ci unsigned char netid = rnet->mport->id; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (netif_msg_intr(rnet)) 2368c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x", 2378c2ecf20Sopenharmony_ci DRV_NAME, sid, tid, info); 2388c2ecf20Sopenharmony_ci if (info == RIONET_DOORBELL_JOIN) { 2398c2ecf20Sopenharmony_ci if (!nets[netid].active[sid]) { 2408c2ecf20Sopenharmony_ci spin_lock(&nets[netid].lock); 2418c2ecf20Sopenharmony_ci list_for_each_entry(peer, &nets[netid].peers, node) { 2428c2ecf20Sopenharmony_ci if (peer->rdev->destid == sid) { 2438c2ecf20Sopenharmony_ci nets[netid].active[sid] = peer->rdev; 2448c2ecf20Sopenharmony_ci nets[netid].nact++; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci spin_unlock(&nets[netid].lock); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci rio_mport_send_doorbell(mport, sid, 2508c2ecf20Sopenharmony_ci RIONET_DOORBELL_JOIN); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci } else if (info == RIONET_DOORBELL_LEAVE) { 2538c2ecf20Sopenharmony_ci spin_lock(&nets[netid].lock); 2548c2ecf20Sopenharmony_ci if (nets[netid].active[sid]) { 2558c2ecf20Sopenharmony_ci nets[netid].active[sid] = NULL; 2568c2ecf20Sopenharmony_ci nets[netid].nact--; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci spin_unlock(&nets[netid].lock); 2598c2ecf20Sopenharmony_ci } else { 2608c2ecf20Sopenharmony_ci if (netif_msg_intr(rnet)) 2618c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: unhandled doorbell\n", 2628c2ecf20Sopenharmony_ci DRV_NAME); 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci int n; 2698c2ecf20Sopenharmony_ci struct net_device *ndev = dev_id; 2708c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (netif_msg_intr(rnet)) 2738c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n", 2748c2ecf20Sopenharmony_ci DRV_NAME, mbox, slot); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci spin_lock(&rnet->lock); 2778c2ecf20Sopenharmony_ci if ((n = rionet_rx_clean(ndev)) != rnet->rx_slot) 2788c2ecf20Sopenharmony_ci rionet_rx_fill(ndev, n); 2798c2ecf20Sopenharmony_ci spin_unlock(&rnet->lock); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct net_device *ndev = dev_id; 2858c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci spin_lock(&rnet->tx_lock); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (netif_msg_intr(rnet)) 2908c2ecf20Sopenharmony_ci printk(KERN_INFO 2918c2ecf20Sopenharmony_ci "%s: outbound message event, mbox %d slot %d\n", 2928c2ecf20Sopenharmony_ci DRV_NAME, mbox, slot); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci while (rnet->tx_cnt && (rnet->ack_slot != slot)) { 2958c2ecf20Sopenharmony_ci /* dma unmap single */ 2968c2ecf20Sopenharmony_ci dev_kfree_skb_irq(rnet->tx_skb[rnet->ack_slot]); 2978c2ecf20Sopenharmony_ci rnet->tx_skb[rnet->ack_slot] = NULL; 2988c2ecf20Sopenharmony_ci ++rnet->ack_slot; 2998c2ecf20Sopenharmony_ci rnet->ack_slot &= (RIONET_TX_RING_SIZE - 1); 3008c2ecf20Sopenharmony_ci rnet->tx_cnt--; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (rnet->tx_cnt < RIONET_TX_RING_SIZE) 3048c2ecf20Sopenharmony_ci netif_wake_queue(ndev); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci spin_unlock(&rnet->tx_lock); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int rionet_open(struct net_device *ndev) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci int i, rc = 0; 3128c2ecf20Sopenharmony_ci struct rionet_peer *peer; 3138c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 3148c2ecf20Sopenharmony_ci unsigned char netid = rnet->mport->id; 3158c2ecf20Sopenharmony_ci unsigned long flags; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (netif_msg_ifup(rnet)) 3188c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: open\n", DRV_NAME); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if ((rc = rio_request_inb_dbell(rnet->mport, 3218c2ecf20Sopenharmony_ci (void *)ndev, 3228c2ecf20Sopenharmony_ci RIONET_DOORBELL_JOIN, 3238c2ecf20Sopenharmony_ci RIONET_DOORBELL_LEAVE, 3248c2ecf20Sopenharmony_ci rionet_dbell_event)) < 0) 3258c2ecf20Sopenharmony_ci goto out; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if ((rc = rio_request_inb_mbox(rnet->mport, 3288c2ecf20Sopenharmony_ci (void *)ndev, 3298c2ecf20Sopenharmony_ci RIONET_MAILBOX, 3308c2ecf20Sopenharmony_ci RIONET_RX_RING_SIZE, 3318c2ecf20Sopenharmony_ci rionet_inb_msg_event)) < 0) 3328c2ecf20Sopenharmony_ci goto out; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if ((rc = rio_request_outb_mbox(rnet->mport, 3358c2ecf20Sopenharmony_ci (void *)ndev, 3368c2ecf20Sopenharmony_ci RIONET_MAILBOX, 3378c2ecf20Sopenharmony_ci RIONET_TX_RING_SIZE, 3388c2ecf20Sopenharmony_ci rionet_outb_msg_event)) < 0) 3398c2ecf20Sopenharmony_ci goto out; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* Initialize inbound message ring */ 3428c2ecf20Sopenharmony_ci for (i = 0; i < RIONET_RX_RING_SIZE; i++) 3438c2ecf20Sopenharmony_ci rnet->rx_skb[i] = NULL; 3448c2ecf20Sopenharmony_ci rnet->rx_slot = 0; 3458c2ecf20Sopenharmony_ci rionet_rx_fill(ndev, 0); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci rnet->tx_slot = 0; 3488c2ecf20Sopenharmony_ci rnet->tx_cnt = 0; 3498c2ecf20Sopenharmony_ci rnet->ack_slot = 0; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci netif_carrier_on(ndev); 3528c2ecf20Sopenharmony_ci netif_start_queue(ndev); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci spin_lock_irqsave(&nets[netid].lock, flags); 3558c2ecf20Sopenharmony_ci list_for_each_entry(peer, &nets[netid].peers, node) { 3568c2ecf20Sopenharmony_ci /* Send a join message */ 3578c2ecf20Sopenharmony_ci rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN); 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nets[netid].lock, flags); 3608c2ecf20Sopenharmony_ci rnet->open = true; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci out: 3638c2ecf20Sopenharmony_ci return rc; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic int rionet_close(struct net_device *ndev) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 3698c2ecf20Sopenharmony_ci struct rionet_peer *peer; 3708c2ecf20Sopenharmony_ci unsigned char netid = rnet->mport->id; 3718c2ecf20Sopenharmony_ci unsigned long flags; 3728c2ecf20Sopenharmony_ci int i; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci if (netif_msg_ifup(rnet)) 3758c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: close %s\n", DRV_NAME, ndev->name); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 3788c2ecf20Sopenharmony_ci netif_carrier_off(ndev); 3798c2ecf20Sopenharmony_ci rnet->open = false; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci for (i = 0; i < RIONET_RX_RING_SIZE; i++) 3828c2ecf20Sopenharmony_ci kfree_skb(rnet->rx_skb[i]); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci spin_lock_irqsave(&nets[netid].lock, flags); 3858c2ecf20Sopenharmony_ci list_for_each_entry(peer, &nets[netid].peers, node) { 3868c2ecf20Sopenharmony_ci if (nets[netid].active[peer->rdev->destid]) { 3878c2ecf20Sopenharmony_ci rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE); 3888c2ecf20Sopenharmony_ci nets[netid].active[peer->rdev->destid] = NULL; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci if (peer->res) 3918c2ecf20Sopenharmony_ci rio_release_outb_dbell(peer->rdev, peer->res); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nets[netid].lock, flags); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN, 3968c2ecf20Sopenharmony_ci RIONET_DOORBELL_LEAVE); 3978c2ecf20Sopenharmony_ci rio_release_inb_mbox(rnet->mport, RIONET_MAILBOX); 3988c2ecf20Sopenharmony_ci rio_release_outb_mbox(rnet->mport, RIONET_MAILBOX); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return 0; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic void rionet_remove_dev(struct device *dev, struct subsys_interface *sif) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct rio_dev *rdev = to_rio_dev(dev); 4068c2ecf20Sopenharmony_ci unsigned char netid = rdev->net->hport->id; 4078c2ecf20Sopenharmony_ci struct rionet_peer *peer; 4088c2ecf20Sopenharmony_ci int state, found = 0; 4098c2ecf20Sopenharmony_ci unsigned long flags; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (!dev_rionet_capable(rdev)) 4128c2ecf20Sopenharmony_ci return; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci spin_lock_irqsave(&nets[netid].lock, flags); 4158c2ecf20Sopenharmony_ci list_for_each_entry(peer, &nets[netid].peers, node) { 4168c2ecf20Sopenharmony_ci if (peer->rdev == rdev) { 4178c2ecf20Sopenharmony_ci list_del(&peer->node); 4188c2ecf20Sopenharmony_ci if (nets[netid].active[rdev->destid]) { 4198c2ecf20Sopenharmony_ci state = atomic_read(&rdev->state); 4208c2ecf20Sopenharmony_ci if (state != RIO_DEVICE_GONE && 4218c2ecf20Sopenharmony_ci state != RIO_DEVICE_INITIALIZING) { 4228c2ecf20Sopenharmony_ci rio_send_doorbell(rdev, 4238c2ecf20Sopenharmony_ci RIONET_DOORBELL_LEAVE); 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci nets[netid].active[rdev->destid] = NULL; 4268c2ecf20Sopenharmony_ci nets[netid].nact--; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci found = 1; 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nets[netid].lock, flags); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (found) { 4358c2ecf20Sopenharmony_ci if (peer->res) 4368c2ecf20Sopenharmony_ci rio_release_outb_dbell(rdev, peer->res); 4378c2ecf20Sopenharmony_ci kfree(peer); 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic void rionet_get_drvinfo(struct net_device *ndev, 4428c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 4478c2ecf20Sopenharmony_ci strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 4488c2ecf20Sopenharmony_ci strlcpy(info->fw_version, "n/a", sizeof(info->fw_version)); 4498c2ecf20Sopenharmony_ci strlcpy(info->bus_info, rnet->mport->name, sizeof(info->bus_info)); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic u32 rionet_get_msglevel(struct net_device *ndev) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return rnet->msg_enable; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic void rionet_set_msglevel(struct net_device *ndev, u32 value) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct rionet_private *rnet = netdev_priv(ndev); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci rnet->msg_enable = value; 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cistatic const struct ethtool_ops rionet_ethtool_ops = { 4678c2ecf20Sopenharmony_ci .get_drvinfo = rionet_get_drvinfo, 4688c2ecf20Sopenharmony_ci .get_msglevel = rionet_get_msglevel, 4698c2ecf20Sopenharmony_ci .set_msglevel = rionet_set_msglevel, 4708c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 4718c2ecf20Sopenharmony_ci}; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic const struct net_device_ops rionet_netdev_ops = { 4748c2ecf20Sopenharmony_ci .ndo_open = rionet_open, 4758c2ecf20Sopenharmony_ci .ndo_stop = rionet_close, 4768c2ecf20Sopenharmony_ci .ndo_start_xmit = rionet_start_xmit, 4778c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 4788c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 4798c2ecf20Sopenharmony_ci}; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci int rc = 0; 4848c2ecf20Sopenharmony_ci struct rionet_private *rnet; 4858c2ecf20Sopenharmony_ci u16 device_id; 4868c2ecf20Sopenharmony_ci const size_t rionet_active_bytes = sizeof(void *) * 4878c2ecf20Sopenharmony_ci RIO_MAX_ROUTE_ENTRIES(mport->sys_size); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci nets[mport->id].active = (struct rio_dev **)__get_free_pages(GFP_KERNEL, 4908c2ecf20Sopenharmony_ci get_order(rionet_active_bytes)); 4918c2ecf20Sopenharmony_ci if (!nets[mport->id].active) { 4928c2ecf20Sopenharmony_ci rc = -ENOMEM; 4938c2ecf20Sopenharmony_ci goto out; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci memset((void *)nets[mport->id].active, 0, rionet_active_bytes); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* Set up private area */ 4988c2ecf20Sopenharmony_ci rnet = netdev_priv(ndev); 4998c2ecf20Sopenharmony_ci rnet->mport = mport; 5008c2ecf20Sopenharmony_ci rnet->open = false; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Set the default MAC address */ 5038c2ecf20Sopenharmony_ci device_id = rio_local_get_device_id(mport); 5048c2ecf20Sopenharmony_ci ndev->dev_addr[0] = 0x00; 5058c2ecf20Sopenharmony_ci ndev->dev_addr[1] = 0x01; 5068c2ecf20Sopenharmony_ci ndev->dev_addr[2] = 0x00; 5078c2ecf20Sopenharmony_ci ndev->dev_addr[3] = 0x01; 5088c2ecf20Sopenharmony_ci ndev->dev_addr[4] = device_id >> 8; 5098c2ecf20Sopenharmony_ci ndev->dev_addr[5] = device_id & 0xff; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci ndev->netdev_ops = &rionet_netdev_ops; 5128c2ecf20Sopenharmony_ci ndev->mtu = RIONET_MAX_MTU; 5138c2ecf20Sopenharmony_ci /* MTU range: 68 - 4082 */ 5148c2ecf20Sopenharmony_ci ndev->min_mtu = ETH_MIN_MTU; 5158c2ecf20Sopenharmony_ci ndev->max_mtu = RIONET_MAX_MTU; 5168c2ecf20Sopenharmony_ci ndev->features = NETIF_F_LLTX; 5178c2ecf20Sopenharmony_ci SET_NETDEV_DEV(ndev, &mport->dev); 5188c2ecf20Sopenharmony_ci ndev->ethtool_ops = &rionet_ethtool_ops; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci spin_lock_init(&rnet->lock); 5218c2ecf20Sopenharmony_ci spin_lock_init(&rnet->tx_lock); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci rnet->msg_enable = RIONET_DEFAULT_MSGLEVEL; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci rc = register_netdev(ndev); 5268c2ecf20Sopenharmony_ci if (rc != 0) { 5278c2ecf20Sopenharmony_ci free_pages((unsigned long)nets[mport->id].active, 5288c2ecf20Sopenharmony_ci get_order(rionet_active_bytes)); 5298c2ecf20Sopenharmony_ci goto out; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: %s %s Version %s, MAC %pM, %s\n", 5338c2ecf20Sopenharmony_ci ndev->name, 5348c2ecf20Sopenharmony_ci DRV_NAME, 5358c2ecf20Sopenharmony_ci DRV_DESC, 5368c2ecf20Sopenharmony_ci DRV_VERSION, 5378c2ecf20Sopenharmony_ci ndev->dev_addr, 5388c2ecf20Sopenharmony_ci mport->name); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci out: 5418c2ecf20Sopenharmony_ci return rc; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic int rionet_add_dev(struct device *dev, struct subsys_interface *sif) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci int rc = -ENODEV; 5478c2ecf20Sopenharmony_ci u32 lsrc_ops, ldst_ops; 5488c2ecf20Sopenharmony_ci struct rionet_peer *peer; 5498c2ecf20Sopenharmony_ci struct net_device *ndev = NULL; 5508c2ecf20Sopenharmony_ci struct rio_dev *rdev = to_rio_dev(dev); 5518c2ecf20Sopenharmony_ci unsigned char netid = rdev->net->hport->id; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci if (netid >= RIONET_MAX_NETS) 5548c2ecf20Sopenharmony_ci return rc; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* 5578c2ecf20Sopenharmony_ci * If first time through this net, make sure local device is rionet 5588c2ecf20Sopenharmony_ci * capable and setup netdev (this step will be skipped in later probes 5598c2ecf20Sopenharmony_ci * on the same net). 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_ci if (!nets[netid].ndev) { 5628c2ecf20Sopenharmony_ci rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR, 5638c2ecf20Sopenharmony_ci &lsrc_ops); 5648c2ecf20Sopenharmony_ci rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR, 5658c2ecf20Sopenharmony_ci &ldst_ops); 5668c2ecf20Sopenharmony_ci if (!is_rionet_capable(lsrc_ops, ldst_ops)) { 5678c2ecf20Sopenharmony_ci printk(KERN_ERR 5688c2ecf20Sopenharmony_ci "%s: local device %s is not network capable\n", 5698c2ecf20Sopenharmony_ci DRV_NAME, rdev->net->hport->name); 5708c2ecf20Sopenharmony_ci goto out; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* Allocate our net_device structure */ 5748c2ecf20Sopenharmony_ci ndev = alloc_etherdev(sizeof(struct rionet_private)); 5758c2ecf20Sopenharmony_ci if (ndev == NULL) { 5768c2ecf20Sopenharmony_ci rc = -ENOMEM; 5778c2ecf20Sopenharmony_ci goto out; 5788c2ecf20Sopenharmony_ci } 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci rc = rionet_setup_netdev(rdev->net->hport, ndev); 5818c2ecf20Sopenharmony_ci if (rc) { 5828c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: failed to setup netdev (rc=%d)\n", 5838c2ecf20Sopenharmony_ci DRV_NAME, rc); 5848c2ecf20Sopenharmony_ci free_netdev(ndev); 5858c2ecf20Sopenharmony_ci goto out; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&nets[netid].peers); 5898c2ecf20Sopenharmony_ci spin_lock_init(&nets[netid].lock); 5908c2ecf20Sopenharmony_ci nets[netid].nact = 0; 5918c2ecf20Sopenharmony_ci nets[netid].ndev = ndev; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* 5958c2ecf20Sopenharmony_ci * If the remote device has mailbox/doorbell capabilities, 5968c2ecf20Sopenharmony_ci * add it to the peer list. 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_ci if (dev_rionet_capable(rdev)) { 5998c2ecf20Sopenharmony_ci struct rionet_private *rnet; 6008c2ecf20Sopenharmony_ci unsigned long flags; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci rnet = netdev_priv(nets[netid].ndev); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci peer = kzalloc(sizeof(*peer), GFP_KERNEL); 6058c2ecf20Sopenharmony_ci if (!peer) { 6068c2ecf20Sopenharmony_ci rc = -ENOMEM; 6078c2ecf20Sopenharmony_ci goto out; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci peer->rdev = rdev; 6108c2ecf20Sopenharmony_ci peer->res = rio_request_outb_dbell(peer->rdev, 6118c2ecf20Sopenharmony_ci RIONET_DOORBELL_JOIN, 6128c2ecf20Sopenharmony_ci RIONET_DOORBELL_LEAVE); 6138c2ecf20Sopenharmony_ci if (!peer->res) { 6148c2ecf20Sopenharmony_ci pr_err("%s: error requesting doorbells\n", DRV_NAME); 6158c2ecf20Sopenharmony_ci kfree(peer); 6168c2ecf20Sopenharmony_ci rc = -ENOMEM; 6178c2ecf20Sopenharmony_ci goto out; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci spin_lock_irqsave(&nets[netid].lock, flags); 6218c2ecf20Sopenharmony_ci list_add_tail(&peer->node, &nets[netid].peers); 6228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nets[netid].lock, flags); 6238c2ecf20Sopenharmony_ci pr_debug("%s: %s add peer %s\n", 6248c2ecf20Sopenharmony_ci DRV_NAME, __func__, rio_name(rdev)); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* If netdev is already opened, send join request to new peer */ 6278c2ecf20Sopenharmony_ci if (rnet->open) 6288c2ecf20Sopenharmony_ci rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return 0; 6328c2ecf20Sopenharmony_ciout: 6338c2ecf20Sopenharmony_ci return rc; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic int rionet_shutdown(struct notifier_block *nb, unsigned long code, 6378c2ecf20Sopenharmony_ci void *unused) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci struct rionet_peer *peer; 6408c2ecf20Sopenharmony_ci unsigned long flags; 6418c2ecf20Sopenharmony_ci int i; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci pr_debug("%s: %s\n", DRV_NAME, __func__); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci for (i = 0; i < RIONET_MAX_NETS; i++) { 6468c2ecf20Sopenharmony_ci if (!nets[i].ndev) 6478c2ecf20Sopenharmony_ci continue; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci spin_lock_irqsave(&nets[i].lock, flags); 6508c2ecf20Sopenharmony_ci list_for_each_entry(peer, &nets[i].peers, node) { 6518c2ecf20Sopenharmony_ci if (nets[i].active[peer->rdev->destid]) { 6528c2ecf20Sopenharmony_ci rio_send_doorbell(peer->rdev, 6538c2ecf20Sopenharmony_ci RIONET_DOORBELL_LEAVE); 6548c2ecf20Sopenharmony_ci nets[i].active[peer->rdev->destid] = NULL; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&nets[i].lock, flags); 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci return NOTIFY_DONE; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic void rionet_remove_mport(struct device *dev, 6648c2ecf20Sopenharmony_ci struct class_interface *class_intf) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci struct rio_mport *mport = to_rio_mport(dev); 6678c2ecf20Sopenharmony_ci struct net_device *ndev; 6688c2ecf20Sopenharmony_ci int id = mport->id; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci pr_debug("%s %s\n", __func__, mport->name); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci WARN(nets[id].nact, "%s called when connected to %d peers\n", 6738c2ecf20Sopenharmony_ci __func__, nets[id].nact); 6748c2ecf20Sopenharmony_ci WARN(!nets[id].ndev, "%s called for mport without NDEV\n", 6758c2ecf20Sopenharmony_ci __func__); 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (nets[id].ndev) { 6788c2ecf20Sopenharmony_ci ndev = nets[id].ndev; 6798c2ecf20Sopenharmony_ci netif_stop_queue(ndev); 6808c2ecf20Sopenharmony_ci unregister_netdev(ndev); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci free_pages((unsigned long)nets[id].active, 6838c2ecf20Sopenharmony_ci get_order(sizeof(void *) * 6848c2ecf20Sopenharmony_ci RIO_MAX_ROUTE_ENTRIES(mport->sys_size))); 6858c2ecf20Sopenharmony_ci nets[id].active = NULL; 6868c2ecf20Sopenharmony_ci free_netdev(ndev); 6878c2ecf20Sopenharmony_ci nets[id].ndev = NULL; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci} 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci#ifdef MODULE 6928c2ecf20Sopenharmony_cistatic struct rio_device_id rionet_id_table[] = { 6938c2ecf20Sopenharmony_ci {RIO_DEVICE(RIO_ANY_ID, RIO_ANY_ID)}, 6948c2ecf20Sopenharmony_ci { 0, } /* terminate list */ 6958c2ecf20Sopenharmony_ci}; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(rapidio, rionet_id_table); 6988c2ecf20Sopenharmony_ci#endif 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic struct subsys_interface rionet_interface = { 7018c2ecf20Sopenharmony_ci .name = "rionet", 7028c2ecf20Sopenharmony_ci .subsys = &rio_bus_type, 7038c2ecf20Sopenharmony_ci .add_dev = rionet_add_dev, 7048c2ecf20Sopenharmony_ci .remove_dev = rionet_remove_dev, 7058c2ecf20Sopenharmony_ci}; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_cistatic struct notifier_block rionet_notifier = { 7088c2ecf20Sopenharmony_ci .notifier_call = rionet_shutdown, 7098c2ecf20Sopenharmony_ci}; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci/* the rio_mport_interface is used to handle local mport devices */ 7128c2ecf20Sopenharmony_cistatic struct class_interface rio_mport_interface __refdata = { 7138c2ecf20Sopenharmony_ci .class = &rio_mport_class, 7148c2ecf20Sopenharmony_ci .add_dev = NULL, 7158c2ecf20Sopenharmony_ci .remove_dev = rionet_remove_mport, 7168c2ecf20Sopenharmony_ci}; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic int __init rionet_init(void) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci int ret; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci ret = register_reboot_notifier(&rionet_notifier); 7238c2ecf20Sopenharmony_ci if (ret) { 7248c2ecf20Sopenharmony_ci pr_err("%s: failed to register reboot notifier (err=%d)\n", 7258c2ecf20Sopenharmony_ci DRV_NAME, ret); 7268c2ecf20Sopenharmony_ci return ret; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci ret = class_interface_register(&rio_mport_interface); 7308c2ecf20Sopenharmony_ci if (ret) { 7318c2ecf20Sopenharmony_ci pr_err("%s: class_interface_register error: %d\n", 7328c2ecf20Sopenharmony_ci DRV_NAME, ret); 7338c2ecf20Sopenharmony_ci return ret; 7348c2ecf20Sopenharmony_ci } 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci return subsys_interface_register(&rionet_interface); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic void __exit rionet_exit(void) 7408c2ecf20Sopenharmony_ci{ 7418c2ecf20Sopenharmony_ci unregister_reboot_notifier(&rionet_notifier); 7428c2ecf20Sopenharmony_ci subsys_interface_unregister(&rionet_interface); 7438c2ecf20Sopenharmony_ci class_interface_unregister(&rio_mport_interface); 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cilate_initcall(rionet_init); 7478c2ecf20Sopenharmony_cimodule_exit(rionet_exit); 748