/*** * * stack/rtnet_module.c - module framework, proc file system * * Copyright (C) 2002 Ulrich Marx * 2003-2006 Jan Kiszka * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("RTnet stack core"); struct class *rtnet_class; struct rtnet_mgr STACK_manager; struct rtnet_mgr RTDEV_manager; EXPORT_SYMBOL_GPL(STACK_manager); EXPORT_SYMBOL_GPL(RTDEV_manager); const char rtnet_rtdm_provider_name[] = "(C) 1999-2008 RTnet Development Team, http://www.rtnet.org"; EXPORT_SYMBOL_GPL(rtnet_rtdm_provider_name); void rtnet_corectl_register(void); void rtnet_corectl_unregister(void); #ifdef CONFIG_XENO_OPT_VFILE /*** * proc filesystem section */ struct xnvfile_directory rtnet_proc_root; EXPORT_SYMBOL_GPL(rtnet_proc_root); static int rtnet_devices_nrt_lock_get(struct xnvfile *vfile) { return mutex_lock_interruptible(&rtnet_devices_nrt_lock); } static void rtnet_devices_nrt_lock_put(struct xnvfile *vfile) { mutex_unlock(&rtnet_devices_nrt_lock); } static struct xnvfile_lock_ops rtnet_devices_nrt_lock_ops = { .get = rtnet_devices_nrt_lock_get, .put = rtnet_devices_nrt_lock_put, }; static void *rtnet_devices_begin(struct xnvfile_regular_iterator *it) { if (it->pos == 0) return VFILE_SEQ_START; return (void *)2UL; } static void *rtnet_devices_next(struct xnvfile_regular_iterator *it) { if (it->pos >= MAX_RT_DEVICES) return NULL; return (void *)2UL; } static int rtnet_devices_show(struct xnvfile_regular_iterator *it, void *data) { struct rtnet_device *rtdev; if (data == NULL) { xnvfile_printf(it, "Index\tName\t\tFlags\n"); return 0; } rtdev = __rtdev_get_by_index(it->pos); if (rtdev == NULL) return VFILE_SEQ_SKIP; xnvfile_printf(it, "%d\t%-15s %s%s%s%s\n", rtdev->ifindex, rtdev->name, (rtdev->flags & IFF_UP) ? "UP" : "DOWN", (rtdev->flags & IFF_BROADCAST) ? " BROADCAST" : "", (rtdev->flags & IFF_LOOPBACK) ? " LOOPBACK" : "", (rtdev->flags & IFF_PROMISC) ? " PROMISC" : ""); return 0; } static struct xnvfile_regular_ops rtnet_devices_vfile_ops = { .begin = rtnet_devices_begin, .next = rtnet_devices_next, .show = rtnet_devices_show, }; static struct xnvfile_regular rtnet_devices_vfile = { .entry = { .lockops = &rtnet_devices_nrt_lock_ops, }, .ops = &rtnet_devices_vfile_ops, }; static int rtnet_rtskb_show(struct xnvfile_regular_iterator *it, void *data) { unsigned int rtskb_len; rtskb_len = ALIGN_RTSKB_STRUCT_LEN + SKB_DATA_ALIGN(RTSKB_SIZE); xnvfile_printf(it, "Statistics\t\tCurrent\tMaximum\n" "rtskb pools\t\t%d\t%d\n" "rtskbs\t\t\t%d\t%d\n" "rtskb memory need\t%d\t%d\n", rtskb_pools, rtskb_pools_max, rtskb_amount, rtskb_amount_max, rtskb_amount * rtskb_len, rtskb_amount_max * rtskb_len); return 0; } static struct xnvfile_regular_ops rtnet_rtskb_vfile_ops = { .show = rtnet_rtskb_show, }; static struct xnvfile_regular rtnet_rtskb_vfile = { .ops = &rtnet_rtskb_vfile_ops, }; static int rtnet_version_show(struct xnvfile_regular_iterator *it, void *data) { const char verstr[] = "RTnet for Xenomai v" XENO_VERSION_STRING "\n" "RTcap: " #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_ADDON_RTCAP) "yes\n" #else "no\n" #endif "rtnetproxy: " #if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_ADDON_PROXY) "yes\n" #else "no\n" #endif "bug checks: " #ifdef CONFIG_XENO_DRIVERS_NET_CHECKED "yes\n" #else "no\n" #endif ; xnvfile_printf(it, "%s", verstr); return 0; } static struct xnvfile_regular_ops rtnet_version_vfile_ops = { .show = rtnet_version_show, }; static struct xnvfile_regular rtnet_version_vfile = { .ops = &rtnet_version_vfile_ops, }; static void *rtnet_stats_begin(struct xnvfile_regular_iterator *it) { return (void *)1UL; } static void *rtnet_stats_next(struct xnvfile_regular_iterator *it) { if (it->pos >= MAX_RT_DEVICES) return NULL; return (void *)1UL; } static int rtnet_stats_show(struct xnvfile_regular_iterator *it, void *data) { struct net_device_stats *stats; struct rtnet_device *rtdev; if (it->pos == 0) { xnvfile_printf(it, "Inter-| Receive " " | Transmit\n"); xnvfile_printf(it, " face |bytes packets errs drop fifo frame " "compressed multicast|bytes packets errs " "drop fifo colls carrier compressed\n"); return 0; } rtdev = __rtdev_get_by_index(it->pos); if (rtdev == NULL) return VFILE_SEQ_SKIP; if (rtdev->get_stats == NULL) { xnvfile_printf(it, "%6s: No statistics available.\n", rtdev->name); return 0; } stats = rtdev->get_stats(rtdev); xnvfile_printf( it, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", rtdev->name, stats->rx_bytes, stats->rx_packets, stats->rx_errors, stats->rx_dropped + stats->rx_missed_errors, stats->rx_fifo_errors, stats->rx_length_errors + stats->rx_over_errors + stats->rx_crc_errors + stats->rx_frame_errors, stats->rx_compressed, stats->multicast, stats->tx_bytes, stats->tx_packets, stats->tx_errors, stats->tx_dropped, stats->tx_fifo_errors, stats->collisions, stats->tx_carrier_errors + stats->tx_aborted_errors + stats->tx_window_errors + stats->tx_heartbeat_errors, stats->tx_compressed); return 0; } static struct xnvfile_regular_ops rtnet_stats_vfile_ops = { .begin = rtnet_stats_begin, .next = rtnet_stats_next, .show = rtnet_stats_show, }; static struct xnvfile_regular rtnet_stats_vfile = { .entry = { .lockops = &rtnet_devices_nrt_lock_ops, }, .ops = &rtnet_stats_vfile_ops, }; static int rtnet_proc_register(void) { int err; err = xnvfile_init_dir("rtnet", &rtnet_proc_root, NULL); if (err < 0) goto error1; err = xnvfile_init_regular("devices", &rtnet_devices_vfile, &rtnet_proc_root); if (err < 0) goto error2; err = xnvfile_init_regular("rtskb", &rtnet_rtskb_vfile, &rtnet_proc_root); if (err < 0) goto error3; err = xnvfile_init_regular("version", &rtnet_version_vfile, &rtnet_proc_root); if (err < 0) goto error4; err = xnvfile_init_regular("stats", &rtnet_stats_vfile, &rtnet_proc_root); if (err < 0) goto error5; return 0; error5: xnvfile_destroy_regular(&rtnet_version_vfile); error4: xnvfile_destroy_regular(&rtnet_rtskb_vfile); error3: xnvfile_destroy_regular(&rtnet_devices_vfile); error2: xnvfile_destroy_dir(&rtnet_proc_root); error1: printk("RTnet: unable to initialize /proc entries\n"); return err; } static void rtnet_proc_unregister(void) { xnvfile_destroy_regular(&rtnet_stats_vfile); xnvfile_destroy_regular(&rtnet_version_vfile); xnvfile_destroy_regular(&rtnet_rtskb_vfile); xnvfile_destroy_regular(&rtnet_devices_vfile); xnvfile_destroy_dir(&rtnet_proc_root); } #endif /* CONFIG_XENO_OPT_VFILE */ /** * rtnet_init() */ int __init rtnet_init(void) { int err = 0; if (!rtdm_available()) return -ENOSYS; printk("\n*** RTnet for Xenomai v" XENO_VERSION_STRING " ***\n\n"); printk("RTnet: initialising real-time networking\n"); rtnet_class = class_create(THIS_MODULE, "rtnet"); if (IS_ERR(rtnet_class)) return PTR_ERR(rtnet_class); if ((err = rtskb_pools_init()) != 0) goto err_out1; #ifdef CONFIG_XENO_OPT_VFILE if ((err = rtnet_proc_register()) != 0) goto err_out2; #endif /* initialize the Stack-Manager */ if ((err = rt_stack_mgr_init(&STACK_manager)) != 0) goto err_out3; /* initialize the RTDEV-Manager */ if ((err = rt_rtdev_mgr_init(&RTDEV_manager)) != 0) goto err_out4; rtnet_chrdev_init(); if ((err = rtwlan_init()) != 0) goto err_out5; if ((err = rtpc_init()) != 0) goto err_out6; rtnet_corectl_register(); return 0; err_out6: rtwlan_exit(); err_out5: rtnet_chrdev_release(); rt_rtdev_mgr_delete(&RTDEV_manager); err_out4: rt_stack_mgr_delete(&STACK_manager); err_out3: #ifdef CONFIG_XENO_OPT_VFILE rtnet_proc_unregister(); err_out2: #endif rtskb_pools_release(); err_out1: class_destroy(rtnet_class); return err; } /** * rtnet_release() */ void __exit rtnet_release(void) { rtnet_corectl_unregister(); rtpc_cleanup(); rtwlan_exit(); rtnet_chrdev_release(); rt_stack_mgr_delete(&STACK_manager); rt_rtdev_mgr_delete(&RTDEV_manager); rtskb_pools_release(); #ifdef CONFIG_XENO_OPT_VFILE rtnet_proc_unregister(); #endif class_destroy(rtnet_class); printk("RTnet: unloaded\n"); } module_init(rtnet_init); module_exit(rtnet_release);