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 */ 60 static bool debug; 61 static bool poll; 62 static struct cpci_hp_controller_ops zt5550_hpc_ops; 63 static struct cpci_hp_controller zt5550_hpc; 64 65 /* Primary cPCI bus bridge device */ 66 static struct pci_dev *bus0_dev; 67 static struct pci_bus *bus0; 68 69 /* Host controller device */ 70 static struct pci_dev *hc_dev; 71 72 /* Host controller register addresses */ 73 static void __iomem *hc_registers; 74 static void __iomem *csr_hc_index; 75 static void __iomem *csr_hc_data; 76 static void __iomem *csr_int_status; 77 static void __iomem *csr_int_mask; 78 79 80 static 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 139 exit_release_region: 140 release_mem_region(pci_resource_start(hc_dev, 1), 141 pci_resource_len(hc_dev, 1)); 142 exit_disable_device: 143 pci_disable_device(hc_dev); 144 return ret; 145 } 146 147 static 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 159 static 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 167 static 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 181 static 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 194 static int zt5550_hc_disable_irq(void) 195 { 196 u8 reg; 197 198 if(hc_dev == NULL) { 199 return -ENODEV; 200 } 201 202 reg = readb(csr_int_mask); 203 reg = reg | ENUM_INT_MASK; 204 writeb(reg, csr_int_mask); 205 return 0; 206 } 207 208 static int zt5550_hc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) 209 { 210 int status; 211 212 status = zt5550_hc_config(pdev); 213 if(status != 0) { 214 return status; 215 } 216 dbg("returned from zt5550_hc_config"); 217 218 memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller)); 219 zt5550_hpc_ops.query_enum = zt5550_hc_query_enum; 220 zt5550_hpc.ops = &zt5550_hpc_ops; 221 if(!poll) { 222 zt5550_hpc.irq = hc_dev->irq; 223 zt5550_hpc.irq_flags = IRQF_SHARED; 224 zt5550_hpc.dev_id = hc_dev; 225 226 zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq; 227 zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq; 228 zt5550_hpc_ops.check_irq = zt5550_hc_check_irq; 229 } else { 230 info("using ENUM# polling mode"); 231 } 232 233 status = cpci_hp_register_controller(&zt5550_hpc); 234 if(status != 0) { 235 err("could not register cPCI hotplug controller"); 236 goto init_hc_error; 237 } 238 dbg("registered controller"); 239 240 /* Look for first device matching cPCI bus's bridge vendor and device IDs */ 241 if(!(bus0_dev = pci_get_device(PCI_VENDOR_ID_DEC, 242 PCI_DEVICE_ID_DEC_21154, NULL))) { 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; 265 init_register_error: 266 cpci_hp_unregister_controller(&zt5550_hpc); 267 init_hc_error: 268 err("status = %d", status); 269 zt5550_hc_cleanup(); 270 return status; 271 272 } 273 274 static 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 283 static 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 }; 287 MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl); 288 289 static 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 296 static 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 312 static void __exit 313 zt5550_exit(void) 314 { 315 pci_unregister_driver(&zt5550_hc_driver); 316 release_region(ENUM_PORT, 1); 317 } 318 319 module_init(zt5550_init); 320 module_exit(zt5550_exit); 321 322 MODULE_AUTHOR(DRIVER_AUTHOR); 323 MODULE_DESCRIPTION(DRIVER_DESC); 324 MODULE_LICENSE("GPL"); 325 module_param(debug, bool, 0644); 326 MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); 327 module_param(poll, bool, 0644); 328 MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not"); 329