1658d439bSTaku Izumi /* 2658d439bSTaku Izumi * FUJITSU Extended Socket Network Device driver 3658d439bSTaku Izumi * Copyright (c) 2015 FUJITSU LIMITED 4658d439bSTaku Izumi * 5658d439bSTaku Izumi * This program is free software; you can redistribute it and/or modify it 6658d439bSTaku Izumi * under the terms and conditions of the GNU General Public License, 7658d439bSTaku Izumi * version 2, as published by the Free Software Foundation. 8658d439bSTaku Izumi * 9658d439bSTaku Izumi * This program is distributed in the hope it will be useful, but WITHOUT 10658d439bSTaku Izumi * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11658d439bSTaku Izumi * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12658d439bSTaku Izumi * more details. 13658d439bSTaku Izumi * 14658d439bSTaku Izumi * You should have received a copy of the GNU General Public License along with 15658d439bSTaku Izumi * this program; if not, see <http://www.gnu.org/licenses/>. 16658d439bSTaku Izumi * 17658d439bSTaku Izumi * The full GNU General Public License is included in this distribution in 18658d439bSTaku Izumi * the file called "COPYING". 19658d439bSTaku Izumi * 20658d439bSTaku Izumi */ 21658d439bSTaku Izumi 22658d439bSTaku Izumi #include <linux/module.h> 23658d439bSTaku Izumi #include <linux/types.h> 24658d439bSTaku Izumi #include <linux/nls.h> 25658d439bSTaku Izumi #include <linux/platform_device.h> 26*2fcbca68STaku Izumi #include <linux/netdevice.h> 27658d439bSTaku Izumi 28658d439bSTaku Izumi #include "fjes.h" 29658d439bSTaku Izumi 30658d439bSTaku Izumi #define MAJ 1 31658d439bSTaku Izumi #define MIN 0 32658d439bSTaku Izumi #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) 33658d439bSTaku Izumi #define DRV_NAME "fjes" 34658d439bSTaku Izumi char fjes_driver_name[] = DRV_NAME; 35658d439bSTaku Izumi char fjes_driver_version[] = DRV_VERSION; 36658d439bSTaku Izumi static const char fjes_driver_string[] = 37658d439bSTaku Izumi "FUJITSU Extended Socket Network Device Driver"; 38658d439bSTaku Izumi static const char fjes_copyright[] = 39658d439bSTaku Izumi "Copyright (c) 2015 FUJITSU LIMITED"; 40658d439bSTaku Izumi 41658d439bSTaku Izumi MODULE_AUTHOR("Taku Izumi <izumi.taku@jp.fujitsu.com>"); 42658d439bSTaku Izumi MODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver"); 43658d439bSTaku Izumi MODULE_LICENSE("GPL"); 44658d439bSTaku Izumi MODULE_VERSION(DRV_VERSION); 45658d439bSTaku Izumi 46658d439bSTaku Izumi static int fjes_acpi_add(struct acpi_device *); 47658d439bSTaku Izumi static int fjes_acpi_remove(struct acpi_device *); 48658d439bSTaku Izumi static acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*); 49658d439bSTaku Izumi 50658d439bSTaku Izumi static int fjes_probe(struct platform_device *); 51658d439bSTaku Izumi static int fjes_remove(struct platform_device *); 52658d439bSTaku Izumi 53*2fcbca68STaku Izumi static int fjes_sw_init(struct fjes_adapter *); 54*2fcbca68STaku Izumi static void fjes_netdev_setup(struct net_device *); 55*2fcbca68STaku Izumi 56658d439bSTaku Izumi static const struct acpi_device_id fjes_acpi_ids[] = { 57658d439bSTaku Izumi {"PNP0C02", 0}, 58658d439bSTaku Izumi {"", 0}, 59658d439bSTaku Izumi }; 60658d439bSTaku Izumi MODULE_DEVICE_TABLE(acpi, fjes_acpi_ids); 61658d439bSTaku Izumi 62658d439bSTaku Izumi static struct acpi_driver fjes_acpi_driver = { 63658d439bSTaku Izumi .name = DRV_NAME, 64658d439bSTaku Izumi .class = DRV_NAME, 65658d439bSTaku Izumi .owner = THIS_MODULE, 66658d439bSTaku Izumi .ids = fjes_acpi_ids, 67658d439bSTaku Izumi .ops = { 68658d439bSTaku Izumi .add = fjes_acpi_add, 69658d439bSTaku Izumi .remove = fjes_acpi_remove, 70658d439bSTaku Izumi }, 71658d439bSTaku Izumi }; 72658d439bSTaku Izumi 73658d439bSTaku Izumi static struct platform_driver fjes_driver = { 74658d439bSTaku Izumi .driver = { 75658d439bSTaku Izumi .name = DRV_NAME, 76658d439bSTaku Izumi .owner = THIS_MODULE, 77658d439bSTaku Izumi }, 78658d439bSTaku Izumi .probe = fjes_probe, 79658d439bSTaku Izumi .remove = fjes_remove, 80658d439bSTaku Izumi }; 81658d439bSTaku Izumi 82658d439bSTaku Izumi static struct resource fjes_resource[] = { 83658d439bSTaku Izumi { 84658d439bSTaku Izumi .flags = IORESOURCE_MEM, 85658d439bSTaku Izumi .start = 0, 86658d439bSTaku Izumi .end = 0, 87658d439bSTaku Izumi }, 88658d439bSTaku Izumi { 89658d439bSTaku Izumi .flags = IORESOURCE_IRQ, 90658d439bSTaku Izumi .start = 0, 91658d439bSTaku Izumi .end = 0, 92658d439bSTaku Izumi }, 93658d439bSTaku Izumi }; 94658d439bSTaku Izumi 95658d439bSTaku Izumi static int fjes_acpi_add(struct acpi_device *device) 96658d439bSTaku Izumi { 97658d439bSTaku Izumi struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; 98658d439bSTaku Izumi char str_buf[sizeof(FJES_ACPI_SYMBOL) + 1]; 99658d439bSTaku Izumi struct platform_device *plat_dev; 100658d439bSTaku Izumi union acpi_object *str; 101658d439bSTaku Izumi acpi_status status; 102658d439bSTaku Izumi int result; 103658d439bSTaku Izumi 104658d439bSTaku Izumi status = acpi_evaluate_object(device->handle, "_STR", NULL, &buffer); 105658d439bSTaku Izumi if (ACPI_FAILURE(status)) 106658d439bSTaku Izumi return -ENODEV; 107658d439bSTaku Izumi 108658d439bSTaku Izumi str = buffer.pointer; 109658d439bSTaku Izumi result = utf16s_to_utf8s((wchar_t *)str->string.pointer, 110658d439bSTaku Izumi str->string.length, UTF16_LITTLE_ENDIAN, 111658d439bSTaku Izumi str_buf, sizeof(str_buf) - 1); 112658d439bSTaku Izumi str_buf[result] = 0; 113658d439bSTaku Izumi 114658d439bSTaku Izumi if (strncmp(FJES_ACPI_SYMBOL, str_buf, strlen(FJES_ACPI_SYMBOL)) != 0) { 115658d439bSTaku Izumi kfree(buffer.pointer); 116658d439bSTaku Izumi return -ENODEV; 117658d439bSTaku Izumi } 118658d439bSTaku Izumi kfree(buffer.pointer); 119658d439bSTaku Izumi 120658d439bSTaku Izumi status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, 121658d439bSTaku Izumi fjes_get_acpi_resource, fjes_resource); 122658d439bSTaku Izumi if (ACPI_FAILURE(status)) 123658d439bSTaku Izumi return -ENODEV; 124658d439bSTaku Izumi 125658d439bSTaku Izumi /* create platform_device */ 126658d439bSTaku Izumi plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource, 127658d439bSTaku Izumi ARRAY_SIZE(fjes_resource)); 128658d439bSTaku Izumi device->driver_data = plat_dev; 129658d439bSTaku Izumi 130658d439bSTaku Izumi return 0; 131658d439bSTaku Izumi } 132658d439bSTaku Izumi 133658d439bSTaku Izumi static int fjes_acpi_remove(struct acpi_device *device) 134658d439bSTaku Izumi { 135658d439bSTaku Izumi struct platform_device *plat_dev; 136658d439bSTaku Izumi 137658d439bSTaku Izumi plat_dev = (struct platform_device *)acpi_driver_data(device); 138658d439bSTaku Izumi platform_device_unregister(plat_dev); 139658d439bSTaku Izumi 140658d439bSTaku Izumi return 0; 141658d439bSTaku Izumi } 142658d439bSTaku Izumi 143658d439bSTaku Izumi static acpi_status 144658d439bSTaku Izumi fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data) 145658d439bSTaku Izumi { 146658d439bSTaku Izumi struct acpi_resource_address32 *addr; 147658d439bSTaku Izumi struct acpi_resource_irq *irq; 148658d439bSTaku Izumi struct resource *res = data; 149658d439bSTaku Izumi 150658d439bSTaku Izumi switch (acpi_res->type) { 151658d439bSTaku Izumi case ACPI_RESOURCE_TYPE_ADDRESS32: 152658d439bSTaku Izumi addr = &acpi_res->data.address32; 153658d439bSTaku Izumi res[0].start = addr->address.minimum; 154658d439bSTaku Izumi res[0].end = addr->address.minimum + 155658d439bSTaku Izumi addr->address.address_length - 1; 156658d439bSTaku Izumi break; 157658d439bSTaku Izumi 158658d439bSTaku Izumi case ACPI_RESOURCE_TYPE_IRQ: 159658d439bSTaku Izumi irq = &acpi_res->data.irq; 160658d439bSTaku Izumi if (irq->interrupt_count != 1) 161658d439bSTaku Izumi return AE_ERROR; 162658d439bSTaku Izumi res[1].start = irq->interrupts[0]; 163658d439bSTaku Izumi res[1].end = irq->interrupts[0]; 164658d439bSTaku Izumi break; 165658d439bSTaku Izumi 166658d439bSTaku Izumi default: 167658d439bSTaku Izumi break; 168658d439bSTaku Izumi } 169658d439bSTaku Izumi 170658d439bSTaku Izumi return AE_OK; 171658d439bSTaku Izumi } 172658d439bSTaku Izumi 173*2fcbca68STaku Izumi static const struct net_device_ops fjes_netdev_ops = { 174*2fcbca68STaku Izumi }; 175*2fcbca68STaku Izumi 176658d439bSTaku Izumi /* fjes_probe - Device Initialization Routine */ 177658d439bSTaku Izumi static int fjes_probe(struct platform_device *plat_dev) 178658d439bSTaku Izumi { 179*2fcbca68STaku Izumi struct fjes_adapter *adapter; 180*2fcbca68STaku Izumi struct net_device *netdev; 181*2fcbca68STaku Izumi struct resource *res; 182*2fcbca68STaku Izumi struct fjes_hw *hw; 183*2fcbca68STaku Izumi int err; 184*2fcbca68STaku Izumi 185*2fcbca68STaku Izumi err = -ENOMEM; 186*2fcbca68STaku Izumi netdev = alloc_netdev_mq(sizeof(struct fjes_adapter), "es%d", 187*2fcbca68STaku Izumi NET_NAME_UNKNOWN, fjes_netdev_setup, 188*2fcbca68STaku Izumi FJES_MAX_QUEUES); 189*2fcbca68STaku Izumi 190*2fcbca68STaku Izumi if (!netdev) 191*2fcbca68STaku Izumi goto err_out; 192*2fcbca68STaku Izumi 193*2fcbca68STaku Izumi SET_NETDEV_DEV(netdev, &plat_dev->dev); 194*2fcbca68STaku Izumi 195*2fcbca68STaku Izumi dev_set_drvdata(&plat_dev->dev, netdev); 196*2fcbca68STaku Izumi adapter = netdev_priv(netdev); 197*2fcbca68STaku Izumi adapter->netdev = netdev; 198*2fcbca68STaku Izumi adapter->plat_dev = plat_dev; 199*2fcbca68STaku Izumi hw = &adapter->hw; 200*2fcbca68STaku Izumi hw->back = adapter; 201*2fcbca68STaku Izumi 202*2fcbca68STaku Izumi /* setup the private structure */ 203*2fcbca68STaku Izumi err = fjes_sw_init(adapter); 204*2fcbca68STaku Izumi if (err) 205*2fcbca68STaku Izumi goto err_free_netdev; 206*2fcbca68STaku Izumi 207*2fcbca68STaku Izumi adapter->force_reset = false; 208*2fcbca68STaku Izumi adapter->open_guard = false; 209*2fcbca68STaku Izumi 210*2fcbca68STaku Izumi res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); 211*2fcbca68STaku Izumi hw->hw_res.start = res->start; 212*2fcbca68STaku Izumi hw->hw_res.size = res->end - res->start + 1; 213*2fcbca68STaku Izumi hw->hw_res.irq = platform_get_irq(plat_dev, 0); 214*2fcbca68STaku Izumi err = fjes_hw_init(&adapter->hw); 215*2fcbca68STaku Izumi if (err) 216*2fcbca68STaku Izumi goto err_free_netdev; 217*2fcbca68STaku Izumi 218*2fcbca68STaku Izumi /* setup MAC address (02:00:00:00:00:[epid])*/ 219*2fcbca68STaku Izumi netdev->dev_addr[0] = 2; 220*2fcbca68STaku Izumi netdev->dev_addr[1] = 0; 221*2fcbca68STaku Izumi netdev->dev_addr[2] = 0; 222*2fcbca68STaku Izumi netdev->dev_addr[3] = 0; 223*2fcbca68STaku Izumi netdev->dev_addr[4] = 0; 224*2fcbca68STaku Izumi netdev->dev_addr[5] = hw->my_epid; /* EPID */ 225*2fcbca68STaku Izumi 226*2fcbca68STaku Izumi err = register_netdev(netdev); 227*2fcbca68STaku Izumi if (err) 228*2fcbca68STaku Izumi goto err_hw_exit; 229*2fcbca68STaku Izumi 230*2fcbca68STaku Izumi netif_carrier_off(netdev); 231*2fcbca68STaku Izumi 232658d439bSTaku Izumi return 0; 233*2fcbca68STaku Izumi 234*2fcbca68STaku Izumi err_hw_exit: 235*2fcbca68STaku Izumi fjes_hw_exit(&adapter->hw); 236*2fcbca68STaku Izumi err_free_netdev: 237*2fcbca68STaku Izumi free_netdev(netdev); 238*2fcbca68STaku Izumi err_out: 239*2fcbca68STaku Izumi return err; 240658d439bSTaku Izumi } 241658d439bSTaku Izumi 242658d439bSTaku Izumi /* fjes_remove - Device Removal Routine */ 243658d439bSTaku Izumi static int fjes_remove(struct platform_device *plat_dev) 244658d439bSTaku Izumi { 245*2fcbca68STaku Izumi struct net_device *netdev = dev_get_drvdata(&plat_dev->dev); 246*2fcbca68STaku Izumi struct fjes_adapter *adapter = netdev_priv(netdev); 247*2fcbca68STaku Izumi struct fjes_hw *hw = &adapter->hw; 248*2fcbca68STaku Izumi 249*2fcbca68STaku Izumi unregister_netdev(netdev); 250*2fcbca68STaku Izumi 251*2fcbca68STaku Izumi fjes_hw_exit(hw); 252*2fcbca68STaku Izumi 253*2fcbca68STaku Izumi free_netdev(netdev); 254*2fcbca68STaku Izumi 255658d439bSTaku Izumi return 0; 256658d439bSTaku Izumi } 257658d439bSTaku Izumi 258*2fcbca68STaku Izumi static int fjes_sw_init(struct fjes_adapter *adapter) 259*2fcbca68STaku Izumi { 260*2fcbca68STaku Izumi return 0; 261*2fcbca68STaku Izumi } 262*2fcbca68STaku Izumi 263*2fcbca68STaku Izumi /* fjes_netdev_setup - netdevice initialization routine */ 264*2fcbca68STaku Izumi static void fjes_netdev_setup(struct net_device *netdev) 265*2fcbca68STaku Izumi { 266*2fcbca68STaku Izumi ether_setup(netdev); 267*2fcbca68STaku Izumi 268*2fcbca68STaku Izumi netdev->watchdog_timeo = FJES_TX_RETRY_INTERVAL; 269*2fcbca68STaku Izumi netdev->netdev_ops = &fjes_netdev_ops; 270*2fcbca68STaku Izumi netdev->mtu = fjes_support_mtu[0]; 271*2fcbca68STaku Izumi netdev->flags |= IFF_BROADCAST; 272*2fcbca68STaku Izumi netdev->features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER; 273*2fcbca68STaku Izumi } 274*2fcbca68STaku Izumi 275658d439bSTaku Izumi /* fjes_init_module - Driver Registration Routine */ 276658d439bSTaku Izumi static int __init fjes_init_module(void) 277658d439bSTaku Izumi { 278658d439bSTaku Izumi int result; 279658d439bSTaku Izumi 280658d439bSTaku Izumi pr_info("%s - version %s - %s\n", 281658d439bSTaku Izumi fjes_driver_string, fjes_driver_version, fjes_copyright); 282658d439bSTaku Izumi 283658d439bSTaku Izumi result = platform_driver_register(&fjes_driver); 284658d439bSTaku Izumi if (result < 0) 285658d439bSTaku Izumi return result; 286658d439bSTaku Izumi 287658d439bSTaku Izumi result = acpi_bus_register_driver(&fjes_acpi_driver); 288658d439bSTaku Izumi if (result < 0) 289658d439bSTaku Izumi goto fail_acpi_driver; 290658d439bSTaku Izumi 291658d439bSTaku Izumi return 0; 292658d439bSTaku Izumi 293658d439bSTaku Izumi fail_acpi_driver: 294658d439bSTaku Izumi platform_driver_unregister(&fjes_driver); 295658d439bSTaku Izumi return result; 296658d439bSTaku Izumi } 297658d439bSTaku Izumi 298658d439bSTaku Izumi module_init(fjes_init_module); 299658d439bSTaku Izumi 300658d439bSTaku Izumi /* fjes_exit_module - Driver Exit Cleanup Routine */ 301658d439bSTaku Izumi static void __exit fjes_exit_module(void) 302658d439bSTaku Izumi { 303658d439bSTaku Izumi acpi_bus_unregister_driver(&fjes_acpi_driver); 304658d439bSTaku Izumi platform_driver_unregister(&fjes_driver); 305658d439bSTaku Izumi } 306658d439bSTaku Izumi 307658d439bSTaku Izumi module_exit(fjes_exit_module); 308