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/config.h> 34 #include <linux/module.h> 35 #include <linux/moduleparam.h> 36 #include <linux/init.h> 37 #include <linux/errno.h> 38 #include <linux/pci.h> 39 #include <linux/signal.h> /* SA_SHIRQ */ 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 int debug; 61 static int 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 %lx", pci_resource_start(hc_dev, 1)); 99 dbg("pci resource len %lx", 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 %lx @ %lx", 112 pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1)); 113 ret = -ENODEV; 114 goto exit_release_region; 115 } 116 117 csr_hc_index = hc_registers + CSR_HCINDEX; 118 csr_hc_data = hc_registers + CSR_HCDATA; 119 csr_int_status = hc_registers + CSR_INTSTAT; 120 csr_int_mask = hc_registers + CSR_INTMASK; 121 122 /* 123 * Disable host control, fault and serial interrupts 124 */ 125 dbg("disabling host control, fault and serial interrupts"); 126 writeb((u8) HC_INT_MASK_REG, csr_hc_index); 127 writeb((u8) ALL_INDEXED_INTS_MASK, csr_hc_data); 128 dbg("disabled host control, fault and serial interrupts"); 129 130 /* 131 * Disable timer0, timer1 and ENUM interrupts 132 */ 133 dbg("disabling timer0, timer1 and ENUM interrupts"); 134 writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask); 135 dbg("disabled timer0, timer1 and ENUM interrupts"); 136 return 0; 137 138 exit_release_region: 139 release_mem_region(pci_resource_start(hc_dev, 1), 140 pci_resource_len(hc_dev, 1)); 141 exit_disable_device: 142 pci_disable_device(hc_dev); 143 return ret; 144 } 145 146 static int zt5550_hc_cleanup(void) 147 { 148 if(!hc_dev) 149 return -ENODEV; 150 151 iounmap(hc_registers); 152 release_mem_region(pci_resource_start(hc_dev, 1), 153 pci_resource_len(hc_dev, 1)); 154 pci_disable_device(hc_dev); 155 return 0; 156 } 157 158 static int zt5550_hc_query_enum(void) 159 { 160 u8 value; 161 162 value = inb_p(ENUM_PORT); 163 return ((value & ENUM_MASK) == ENUM_MASK); 164 } 165 166 static int zt5550_hc_check_irq(void *dev_id) 167 { 168 int ret; 169 u8 reg; 170 171 ret = 0; 172 if(dev_id == zt5550_hpc.dev_id) { 173 reg = readb(csr_int_status); 174 if(reg) 175 ret = 1; 176 } 177 return ret; 178 } 179 180 static int zt5550_hc_enable_irq(void) 181 { 182 u8 reg; 183 184 if(hc_dev == NULL) { 185 return -ENODEV; 186 } 187 reg = readb(csr_int_mask); 188 reg = reg & ~ENUM_INT_MASK; 189 writeb(reg, csr_int_mask); 190 return 0; 191 } 192 193 static int zt5550_hc_disable_irq(void) 194 { 195 u8 reg; 196 197 if(hc_dev == NULL) { 198 return -ENODEV; 199 } 200 201 reg = readb(csr_int_mask); 202 reg = reg | ENUM_INT_MASK; 203 writeb(reg, csr_int_mask); 204 return 0; 205 } 206 207 static 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 = SA_SHIRQ; 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 if(!(bus0_dev = pci_get_device(PCI_VENDOR_ID_DEC, 241 PCI_DEVICE_ID_DEC_21154, NULL))) { 242 status = -ENODEV; 243 goto init_register_error; 244 } 245 bus0 = bus0_dev->subordinate; 246 pci_dev_put(bus0_dev); 247 248 status = cpci_hp_register_bus(bus0, 0x0a, 0x0f); 249 if(status != 0) { 250 err("could not register cPCI hotplug bus"); 251 goto init_register_error; 252 } 253 dbg("registered bus"); 254 255 status = cpci_hp_start(); 256 if(status != 0) { 257 err("could not started cPCI hotplug system"); 258 cpci_hp_unregister_bus(bus0); 259 goto init_register_error; 260 } 261 dbg("started cpci hp system"); 262 263 return 0; 264 init_register_error: 265 cpci_hp_unregister_controller(&zt5550_hpc); 266 init_hc_error: 267 err("status = %d", status); 268 zt5550_hc_cleanup(); 269 return status; 270 271 } 272 273 static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev) 274 { 275 cpci_hp_stop(); 276 cpci_hp_unregister_bus(bus0); 277 cpci_hp_unregister_controller(&zt5550_hpc); 278 zt5550_hc_cleanup(); 279 } 280 281 282 static struct pci_device_id zt5550_hc_pci_tbl[] = { 283 { PCI_VENDOR_ID_ZIATECH, PCI_DEVICE_ID_ZIATECH_5550_HC, PCI_ANY_ID, PCI_ANY_ID, }, 284 { 0, } 285 }; 286 MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl); 287 288 static struct pci_driver zt5550_hc_driver = { 289 .name = "zt5550_hc", 290 .id_table = zt5550_hc_pci_tbl, 291 .probe = zt5550_hc_init_one, 292 .remove = __devexit_p(zt5550_hc_remove_one), 293 }; 294 295 static int __init zt5550_init(void) 296 { 297 struct resource* r; 298 299 info(DRIVER_DESC " version: " DRIVER_VERSION); 300 r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); 301 if(!r) 302 return -EBUSY; 303 304 return pci_register_driver(&zt5550_hc_driver); 305 } 306 307 static void __exit 308 zt5550_exit(void) 309 { 310 pci_unregister_driver(&zt5550_hc_driver); 311 release_region(ENUM_PORT, 1); 312 } 313 314 module_init(zt5550_init); 315 module_exit(zt5550_exit); 316 317 MODULE_AUTHOR(DRIVER_AUTHOR); 318 MODULE_DESCRIPTION(DRIVER_DESC); 319 MODULE_LICENSE("GPL"); 320 module_param(debug, bool, 0644); 321 MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); 322 module_param(poll, bool, 0644); 323 MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not"); 324