1/* 2 * cpcihp_zt5550.c 3 * 4 * Intel/Ziatech ZT5550 CompactPCI Host Controller driver 5 * 6 * Copyright 2002 SOMA Networks, Inc. 7 * Copyright 2001 Intel San Luis Obispo 8 * Copyright 2000,2001 MontaVista Software Inc. 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 16 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 17 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 18 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 22 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 23 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * You should have received a copy of the GNU General Public License along 27 * with this program; if not, write to the Free Software Foundation, Inc., 28 * 675 Mass Ave, Cambridge, MA 02139, USA. 29 * 30 * Send feedback to <scottm@somanetworks.com> 31 */ 32 33#include <linux/module.h> 34#include <linux/moduleparam.h> 35#include <linux/init.h> 36#include <linux/errno.h> 37#include <linux/pci.h> 38#include <linux/interrupt.h> 39#include <linux/signal.h> /* IRQF_SHARED */ 40#include "cpci_hotplug.h" 41#include "cpcihp_zt5550.h" 42 43#define DRIVER_VERSION "0.2" 44#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" 45#define DRIVER_DESC "ZT5550 CompactPCI Hot Plug Driver" 46 47#define MY_NAME "cpcihp_zt5550" 48 49#define dbg(format, arg...) \ 50 do { \ 51 if (debug) \ 52 printk (KERN_DEBUG "%s: " format "\n", \ 53 MY_NAME , ## arg); \ 54 } while (0) 55#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) 56#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) 57#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) 58 59/* local variables */ 60static bool debug; 61static bool poll; 62static struct cpci_hp_controller_ops zt5550_hpc_ops; 63static struct cpci_hp_controller zt5550_hpc; 64 65/* Primary cPCI bus bridge device */ 66static struct pci_dev *bus0_dev; 67static struct pci_bus *bus0; 68 69/* Host controller device */ 70static struct pci_dev *hc_dev; 71 72/* Host controller register addresses */ 73static void __iomem *hc_registers; 74static void __iomem *csr_hc_index; 75static void __iomem *csr_hc_data; 76static void __iomem *csr_int_status; 77static void __iomem *csr_int_mask; 78 79 80static int zt5550_hc_config(struct pci_dev *pdev) 81{ 82 int ret; 83 84 /* Since we know that no boards exist with two HC chips, treat it as an error */ 85 if (hc_dev) { 86 err("too many host controller devices?"); 87 return -EBUSY; 88 } 89 90 ret = pci_enable_device(pdev); 91 if (ret) { 92 err("cannot enable %s\n", pci_name(pdev)); 93 return ret; 94 } 95 96 hc_dev = pdev; 97 dbg("hc_dev = %p", hc_dev); 98 dbg("pci resource start %llx", (unsigned long long)pci_resource_start(hc_dev, 1)); 99 dbg("pci resource len %llx", (unsigned long long)pci_resource_len(hc_dev, 1)); 100 101 if (!request_mem_region(pci_resource_start(hc_dev, 1), 102 pci_resource_len(hc_dev, 1), MY_NAME)) { 103 err("cannot reserve MMIO region"); 104 ret = -ENOMEM; 105 goto exit_disable_device; 106 } 107 108 hc_registers = 109 ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1)); 110 if (!hc_registers) { 111 err("cannot remap MMIO region %llx @ %llx", 112 (unsigned long long)pci_resource_len(hc_dev, 1), 113 (unsigned long long)pci_resource_start(hc_dev, 1)); 114 ret = -ENODEV; 115 goto exit_release_region; 116 } 117 118 csr_hc_index = hc_registers + CSR_HCINDEX; 119 csr_hc_data = hc_registers + CSR_HCDATA; 120 csr_int_status = hc_registers + CSR_INTSTAT; 121 csr_int_mask = hc_registers + CSR_INTMASK; 122 123 /* 124 * Disable host control, fault and serial interrupts 125 */ 126 dbg("disabling host control, fault and serial interrupts"); 127 writeb((u8) HC_INT_MASK_REG, csr_hc_index); 128 writeb((u8) ALL_INDEXED_INTS_MASK, csr_hc_data); 129 dbg("disabled host control, fault and serial interrupts"); 130 131 /* 132 * Disable timer0, timer1 and ENUM interrupts 133 */ 134 dbg("disabling timer0, timer1 and ENUM interrupts"); 135 writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask); 136 dbg("disabled timer0, timer1 and ENUM interrupts"); 137 return 0; 138 139exit_release_region: 140 release_mem_region(pci_resource_start(hc_dev, 1), 141 pci_resource_len(hc_dev, 1)); 142exit_disable_device: 143 pci_disable_device(hc_dev); 144 return ret; 145} 146 147static int zt5550_hc_cleanup(void) 148{ 149 if (!hc_dev) 150 return -ENODEV; 151 152 iounmap(hc_registers); 153 release_mem_region(pci_resource_start(hc_dev, 1), 154 pci_resource_len(hc_dev, 1)); 155 pci_disable_device(hc_dev); 156 return 0; 157} 158 159static int zt5550_hc_query_enum(void) 160{ 161 u8 value; 162 163 value = inb_p(ENUM_PORT); 164 return ((value & ENUM_MASK) == ENUM_MASK); 165} 166 167static int zt5550_hc_check_irq(void *dev_id) 168{ 169 int ret; 170 u8 reg; 171 172 ret = 0; 173 if (dev_id == zt5550_hpc.dev_id) { 174 reg = readb(csr_int_status); 175 if (reg) 176 ret = 1; 177 } 178 return ret; 179} 180 181static int zt5550_hc_enable_irq(void) 182{ 183 u8 reg; 184 185 if (hc_dev == NULL) 186 return -ENODEV; 187 188 reg = readb(csr_int_mask); 189 reg = reg & ~ENUM_INT_MASK; 190 writeb(reg, csr_int_mask); 191 return 0; 192} 193 194static int zt5550_hc_disable_irq(void) 195{ 196 u8 reg; 197 198 if (hc_dev == NULL) 199 return -ENODEV; 200 201 reg = readb(csr_int_mask); 202 reg = reg | ENUM_INT_MASK; 203 writeb(reg, csr_int_mask); 204 return 0; 205} 206 207static int zt5550_hc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) 208{ 209 int status; 210 211 status = zt5550_hc_config(pdev); 212 if (status != 0) 213 return status; 214 215 dbg("returned from zt5550_hc_config"); 216 217 memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller)); 218 zt5550_hpc_ops.query_enum = zt5550_hc_query_enum; 219 zt5550_hpc.ops = &zt5550_hpc_ops; 220 if (!poll) { 221 zt5550_hpc.irq = hc_dev->irq; 222 zt5550_hpc.irq_flags = IRQF_SHARED; 223 zt5550_hpc.dev_id = hc_dev; 224 225 zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq; 226 zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq; 227 zt5550_hpc_ops.check_irq = zt5550_hc_check_irq; 228 } else { 229 info("using ENUM# polling mode"); 230 } 231 232 status = cpci_hp_register_controller(&zt5550_hpc); 233 if (status != 0) { 234 err("could not register cPCI hotplug controller"); 235 goto init_hc_error; 236 } 237 dbg("registered controller"); 238 239 /* Look for first device matching cPCI bus's bridge vendor and device IDs */ 240 bus0_dev = pci_get_device(PCI_VENDOR_ID_DEC, 241 PCI_DEVICE_ID_DEC_21154, NULL); 242 if (!bus0_dev) { 243 status = -ENODEV; 244 goto init_register_error; 245 } 246 bus0 = bus0_dev->subordinate; 247 pci_dev_put(bus0_dev); 248 249 status = cpci_hp_register_bus(bus0, 0x0a, 0x0f); 250 if (status != 0) { 251 err("could not register cPCI hotplug bus"); 252 goto init_register_error; 253 } 254 dbg("registered bus"); 255 256 status = cpci_hp_start(); 257 if (status != 0) { 258 err("could not started cPCI hotplug system"); 259 cpci_hp_unregister_bus(bus0); 260 goto init_register_error; 261 } 262 dbg("started cpci hp system"); 263 264 return 0; 265init_register_error: 266 cpci_hp_unregister_controller(&zt5550_hpc); 267init_hc_error: 268 err("status = %d", status); 269 zt5550_hc_cleanup(); 270 return status; 271 272} 273 274static void zt5550_hc_remove_one(struct pci_dev *pdev) 275{ 276 cpci_hp_stop(); 277 cpci_hp_unregister_bus(bus0); 278 cpci_hp_unregister_controller(&zt5550_hpc); 279 zt5550_hc_cleanup(); 280} 281 282 283static struct pci_device_id zt5550_hc_pci_tbl[] = { 284 { PCI_VENDOR_ID_ZIATECH, PCI_DEVICE_ID_ZIATECH_5550_HC, PCI_ANY_ID, PCI_ANY_ID, }, 285 { 0, } 286}; 287MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl); 288 289static struct pci_driver zt5550_hc_driver = { 290 .name = "zt5550_hc", 291 .id_table = zt5550_hc_pci_tbl, 292 .probe = zt5550_hc_init_one, 293 .remove = zt5550_hc_remove_one, 294}; 295 296static int __init zt5550_init(void) 297{ 298 struct resource *r; 299 int rc; 300 301 info(DRIVER_DESC " version: " DRIVER_VERSION); 302 r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); 303 if (!r) 304 return -EBUSY; 305 306 rc = pci_register_driver(&zt5550_hc_driver); 307 if (rc < 0) 308 release_region(ENUM_PORT, 1); 309 return rc; 310} 311 312static void __exit 313zt5550_exit(void) 314{ 315 pci_unregister_driver(&zt5550_hc_driver); 316 release_region(ENUM_PORT, 1); 317} 318 319module_init(zt5550_init); 320module_exit(zt5550_exit); 321 322MODULE_AUTHOR(DRIVER_AUTHOR); 323MODULE_DESCRIPTION(DRIVER_DESC); 324MODULE_LICENSE("GPL"); 325module_param(debug, bool, 0644); 326MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); 327module_param(poll, bool, 0644); 328MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not"); 329