162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/************************************************************************ 362306a36Sopenharmony_ci * Copyright 2003 Digi International (www.digi.com) 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004 IBM Corporation. All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Contact Information: 862306a36Sopenharmony_ci * Scott H Kilau <Scott_Kilau@digi.com> 962306a36Sopenharmony_ci * Wendy Xiong <wendyx@us.ibm.com> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci ***********************************************************************/ 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/pci.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "jsm.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciMODULE_AUTHOR("Digi International, https://www.digi.com"); 2062306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line"); 2162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define JSM_DRIVER_NAME "jsm" 2462306a36Sopenharmony_ci#define NR_PORTS 32 2562306a36Sopenharmony_ci#define JSM_MINOR_START 0 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistruct uart_driver jsm_uart_driver = { 2862306a36Sopenharmony_ci .owner = THIS_MODULE, 2962306a36Sopenharmony_ci .driver_name = JSM_DRIVER_NAME, 3062306a36Sopenharmony_ci .dev_name = "ttyn", 3162306a36Sopenharmony_ci .major = 0, 3262306a36Sopenharmony_ci .minor = JSM_MINOR_START, 3362306a36Sopenharmony_ci .nr = NR_PORTS, 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev, 3762306a36Sopenharmony_ci pci_channel_state_t state); 3862306a36Sopenharmony_cistatic pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev); 3962306a36Sopenharmony_cistatic void jsm_io_resume(struct pci_dev *pdev); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic const struct pci_error_handlers jsm_err_handler = { 4262306a36Sopenharmony_ci .error_detected = jsm_io_error_detected, 4362306a36Sopenharmony_ci .slot_reset = jsm_io_slot_reset, 4462306a36Sopenharmony_ci .resume = jsm_io_resume, 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciint jsm_debug; 4862306a36Sopenharmony_cimodule_param(jsm_debug, int, 0); 4962306a36Sopenharmony_ciMODULE_PARM_DESC(jsm_debug, "Driver debugging level"); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci int rc = 0; 5462306a36Sopenharmony_ci struct jsm_board *brd; 5562306a36Sopenharmony_ci static int adapter_count; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci rc = pci_enable_device(pdev); 5862306a36Sopenharmony_ci if (rc) { 5962306a36Sopenharmony_ci dev_err(&pdev->dev, "Device enable FAILED\n"); 6062306a36Sopenharmony_ci goto out; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci rc = pci_request_regions(pdev, JSM_DRIVER_NAME); 6462306a36Sopenharmony_ci if (rc) { 6562306a36Sopenharmony_ci dev_err(&pdev->dev, "pci_request_region FAILED\n"); 6662306a36Sopenharmony_ci goto out_disable_device; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci brd = kzalloc(sizeof(*brd), GFP_KERNEL); 7062306a36Sopenharmony_ci if (!brd) { 7162306a36Sopenharmony_ci rc = -ENOMEM; 7262306a36Sopenharmony_ci goto out_release_regions; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* store the info for the board we've found */ 7662306a36Sopenharmony_ci brd->boardnum = adapter_count++; 7762306a36Sopenharmony_ci brd->pci_dev = pdev; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci switch (pdev->device) { 8062306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_2DB9: 8162306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_2DB9PRI: 8262306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_2RJ45: 8362306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_2RJ45PRI: 8462306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_2_422_485: 8562306a36Sopenharmony_ci brd->maxports = 2; 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_4: 8962306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_4_422: 9062306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_4: 9162306a36Sopenharmony_ci case PCIE_DEVICE_ID_NEO_4: 9262306a36Sopenharmony_ci case PCIE_DEVICE_ID_NEO_4RJ45: 9362306a36Sopenharmony_ci case PCIE_DEVICE_ID_NEO_4_IBM: 9462306a36Sopenharmony_ci brd->maxports = 4; 9562306a36Sopenharmony_ci break; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_8: 9862306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_8_422: 9962306a36Sopenharmony_ci case PCI_DEVICE_ID_DIGI_NEO_8: 10062306a36Sopenharmony_ci case PCIE_DEVICE_ID_NEO_8: 10162306a36Sopenharmony_ci case PCIE_DEVICE_ID_NEO_8RJ45: 10262306a36Sopenharmony_ci brd->maxports = 8; 10362306a36Sopenharmony_ci break; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci default: 10662306a36Sopenharmony_ci brd->maxports = 1; 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci spin_lock_init(&brd->bd_intr_lock); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* store which revision we have */ 11362306a36Sopenharmony_ci brd->rev = pdev->revision; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci brd->irq = pdev->irq; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci switch (pdev->device) { 11862306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_4: 11962306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_4_422: 12062306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_8: 12162306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_8_422: 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci jsm_dbg(INIT, &brd->pci_dev, 12462306a36Sopenharmony_ci "jsm_found_board - Classic adapter\n"); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * For PCI ClassicBoards 12862306a36Sopenharmony_ci * PCI Local Address (.i.e. "resource" number) space 12962306a36Sopenharmony_ci * 0 PLX Memory Mapped Config 13062306a36Sopenharmony_ci * 1 PLX I/O Mapped Config 13162306a36Sopenharmony_ci * 2 I/O Mapped UARTs and Status 13262306a36Sopenharmony_ci * 3 Memory Mapped VPD 13362306a36Sopenharmony_ci * 4 Memory Mapped UARTs and Status 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Get the PCI Base Address Registers */ 13762306a36Sopenharmony_ci brd->membase = pci_resource_start(pdev, 4); 13862306a36Sopenharmony_ci brd->membase_end = pci_resource_end(pdev, 4); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci if (brd->membase & 0x1) 14162306a36Sopenharmony_ci brd->membase &= ~0x3; 14262306a36Sopenharmony_ci else 14362306a36Sopenharmony_ci brd->membase &= ~0xF; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci brd->iobase = pci_resource_start(pdev, 1); 14662306a36Sopenharmony_ci brd->iobase_end = pci_resource_end(pdev, 1); 14762306a36Sopenharmony_ci brd->iobase = ((unsigned int)(brd->iobase)) & 0xFFFE; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* Assign the board_ops struct */ 15062306a36Sopenharmony_ci brd->bd_ops = &jsm_cls_ops; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci brd->bd_uart_offset = 0x8; 15362306a36Sopenharmony_ci brd->bd_dividend = 921600; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci brd->re_map_membase = ioremap(brd->membase, 15662306a36Sopenharmony_ci pci_resource_len(pdev, 4)); 15762306a36Sopenharmony_ci if (!brd->re_map_membase) { 15862306a36Sopenharmony_ci dev_err(&pdev->dev, 15962306a36Sopenharmony_ci "Card has no PCI Memory resources, failing board.\n"); 16062306a36Sopenharmony_ci rc = -ENOMEM; 16162306a36Sopenharmony_ci goto out_kfree_brd; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* 16562306a36Sopenharmony_ci * Enable Local Interrupt 1 (0x1), 16662306a36Sopenharmony_ci * Local Interrupt 1 Polarity Active high (0x2), 16762306a36Sopenharmony_ci * Enable PCI interrupt (0x43) 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ci outb(0x43, brd->iobase + 0x4c); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_2DB9: 17462306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_2DB9PRI: 17562306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_2RJ45: 17662306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_2RJ45PRI: 17762306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_2_422_485: 17862306a36Sopenharmony_ci case PCI_DEVICE_ID_NEO_4: 17962306a36Sopenharmony_ci case PCIE_DEVICE_ID_NEO_4: 18062306a36Sopenharmony_ci case PCIE_DEVICE_ID_NEO_4RJ45: 18162306a36Sopenharmony_ci case PCIE_DEVICE_ID_NEO_4_IBM: 18262306a36Sopenharmony_ci case PCI_DEVICE_ID_DIGI_NEO_8: 18362306a36Sopenharmony_ci case PCIE_DEVICE_ID_NEO_8: 18462306a36Sopenharmony_ci case PCIE_DEVICE_ID_NEO_8RJ45: 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci jsm_dbg(INIT, &brd->pci_dev, "jsm_found_board - NEO adapter\n"); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* get the PCI Base Address Registers */ 18962306a36Sopenharmony_ci brd->membase = pci_resource_start(pdev, 0); 19062306a36Sopenharmony_ci brd->membase_end = pci_resource_end(pdev, 0); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (brd->membase & 1) 19362306a36Sopenharmony_ci brd->membase &= ~0x3; 19462306a36Sopenharmony_ci else 19562306a36Sopenharmony_ci brd->membase &= ~0xF; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* Assign the board_ops struct */ 19862306a36Sopenharmony_ci brd->bd_ops = &jsm_neo_ops; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci brd->bd_uart_offset = 0x200; 20162306a36Sopenharmony_ci brd->bd_dividend = 921600; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci brd->re_map_membase = ioremap(brd->membase, 20462306a36Sopenharmony_ci pci_resource_len(pdev, 0)); 20562306a36Sopenharmony_ci if (!brd->re_map_membase) { 20662306a36Sopenharmony_ci dev_err(&pdev->dev, 20762306a36Sopenharmony_ci "Card has no PCI Memory resources, failing board.\n"); 20862306a36Sopenharmony_ci rc = -ENOMEM; 20962306a36Sopenharmony_ci goto out_kfree_brd; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci default: 21462306a36Sopenharmony_ci rc = -ENXIO; 21562306a36Sopenharmony_ci goto out_kfree_brd; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci rc = request_irq(brd->irq, brd->bd_ops->intr, IRQF_SHARED, "JSM", brd); 21962306a36Sopenharmony_ci if (rc) { 22062306a36Sopenharmony_ci dev_warn(&pdev->dev, "Failed to hook IRQ %d\n", brd->irq); 22162306a36Sopenharmony_ci goto out_iounmap; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci rc = jsm_tty_init(brd); 22562306a36Sopenharmony_ci if (rc < 0) { 22662306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't init tty devices (%d)\n", rc); 22762306a36Sopenharmony_ci rc = -ENXIO; 22862306a36Sopenharmony_ci goto out_free_irq; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci rc = jsm_uart_port_init(brd); 23262306a36Sopenharmony_ci if (rc < 0) { 23362306a36Sopenharmony_ci /* XXX: leaking all resources from jsm_tty_init here! */ 23462306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't init uart port (%d)\n", rc); 23562306a36Sopenharmony_ci rc = -ENXIO; 23662306a36Sopenharmony_ci goto out_free_irq; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci /* Log the information about the board */ 24062306a36Sopenharmony_ci dev_info(&pdev->dev, "board %d: Digi Classic/Neo (rev %d), irq %d\n", 24162306a36Sopenharmony_ci adapter_count, brd->rev, brd->irq); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci pci_set_drvdata(pdev, brd); 24462306a36Sopenharmony_ci pci_save_state(pdev); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci out_free_irq: 24862306a36Sopenharmony_ci jsm_remove_uart_port(brd); 24962306a36Sopenharmony_ci free_irq(brd->irq, brd); 25062306a36Sopenharmony_ci out_iounmap: 25162306a36Sopenharmony_ci iounmap(brd->re_map_membase); 25262306a36Sopenharmony_ci out_kfree_brd: 25362306a36Sopenharmony_ci kfree(brd); 25462306a36Sopenharmony_ci out_release_regions: 25562306a36Sopenharmony_ci pci_release_regions(pdev); 25662306a36Sopenharmony_ci out_disable_device: 25762306a36Sopenharmony_ci pci_disable_device(pdev); 25862306a36Sopenharmony_ci out: 25962306a36Sopenharmony_ci return rc; 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void jsm_remove_one(struct pci_dev *pdev) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct jsm_board *brd = pci_get_drvdata(pdev); 26562306a36Sopenharmony_ci int i = 0; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci switch (pdev->device) { 26862306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_4: 26962306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_4_422: 27062306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_8: 27162306a36Sopenharmony_ci case PCI_DEVICE_ID_CLASSIC_8_422: 27262306a36Sopenharmony_ci /* Tell card not to interrupt anymore. */ 27362306a36Sopenharmony_ci outb(0x0, brd->iobase + 0x4c); 27462306a36Sopenharmony_ci break; 27562306a36Sopenharmony_ci default: 27662306a36Sopenharmony_ci break; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci jsm_remove_uart_port(brd); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci free_irq(brd->irq, brd); 28262306a36Sopenharmony_ci iounmap(brd->re_map_membase); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Free all allocated channels structs */ 28562306a36Sopenharmony_ci for (i = 0; i < brd->maxports; i++) { 28662306a36Sopenharmony_ci if (brd->channels[i]) { 28762306a36Sopenharmony_ci kfree(brd->channels[i]->ch_rqueue); 28862306a36Sopenharmony_ci kfree(brd->channels[i]->ch_equeue); 28962306a36Sopenharmony_ci kfree(brd->channels[i]); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci pci_release_regions(pdev); 29462306a36Sopenharmony_ci pci_disable_device(pdev); 29562306a36Sopenharmony_ci kfree(brd); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic const struct pci_device_id jsm_pci_tbl[] = { 29962306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 }, 30062306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 }, 30162306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 }, 30262306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 }, 30362306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 }, 30462306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 }, 30562306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_4), 0, 0, 6 }, 30662306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_1_422), 0, 0, 7 }, 30762306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_1_422_485), 0, 0, 8 }, 30862306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2_422_485), 0, 0, 9 }, 30962306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8), 0, 0, 10 }, 31062306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4), 0, 0, 11 }, 31162306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4RJ45), 0, 0, 12 }, 31262306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_8RJ45), 0, 0, 13 }, 31362306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_4), 0, 0, 14 }, 31462306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_4_422), 0, 0, 15 }, 31562306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_8), 0, 0, 16 }, 31662306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_CLASSIC_8_422), 0, 0, 17 }, 31762306a36Sopenharmony_ci { 0, } 31862306a36Sopenharmony_ci}; 31962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, jsm_pci_tbl); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic struct pci_driver jsm_driver = { 32262306a36Sopenharmony_ci .name = JSM_DRIVER_NAME, 32362306a36Sopenharmony_ci .id_table = jsm_pci_tbl, 32462306a36Sopenharmony_ci .probe = jsm_probe_one, 32562306a36Sopenharmony_ci .remove = jsm_remove_one, 32662306a36Sopenharmony_ci .err_handler = &jsm_err_handler, 32762306a36Sopenharmony_ci}; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic pci_ers_result_t jsm_io_error_detected(struct pci_dev *pdev, 33062306a36Sopenharmony_ci pci_channel_state_t state) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct jsm_board *brd = pci_get_drvdata(pdev); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci jsm_remove_uart_port(brd); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic pci_ers_result_t jsm_io_slot_reset(struct pci_dev *pdev) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci int rc; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci rc = pci_enable_device(pdev); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (rc) 34662306a36Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci pci_set_master(pdev); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_cistatic void jsm_io_resume(struct pci_dev *pdev) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct jsm_board *brd = pci_get_drvdata(pdev); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci pci_restore_state(pdev); 35862306a36Sopenharmony_ci pci_save_state(pdev); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci jsm_uart_port_init(brd); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic int __init jsm_init_module(void) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci int rc; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci rc = uart_register_driver(&jsm_uart_driver); 36862306a36Sopenharmony_ci if (!rc) { 36962306a36Sopenharmony_ci rc = pci_register_driver(&jsm_driver); 37062306a36Sopenharmony_ci if (rc) 37162306a36Sopenharmony_ci uart_unregister_driver(&jsm_uart_driver); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci return rc; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic void __exit jsm_exit_module(void) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci pci_unregister_driver(&jsm_driver); 37962306a36Sopenharmony_ci uart_unregister_driver(&jsm_uart_driver); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cimodule_init(jsm_init_module); 38362306a36Sopenharmony_cimodule_exit(jsm_exit_module); 384