18cfab3cfSBjorn Helgaas // SPDX-License-Identifier: GPL-2.0 2080b47deSLogan Gunthorpe /* 3080b47deSLogan Gunthorpe * Microsemi Switchtec(tm) PCIe Management Driver 4080b47deSLogan Gunthorpe * Copyright (c) 2017, Microsemi Corporation 5080b47deSLogan Gunthorpe */ 6080b47deSLogan Gunthorpe 75a1c269fSLogan Gunthorpe #include <linux/switchtec.h> 852eabba5SLogan Gunthorpe #include <linux/switchtec_ioctl.h> 952eabba5SLogan Gunthorpe 10080b47deSLogan Gunthorpe #include <linux/interrupt.h> 11080b47deSLogan Gunthorpe #include <linux/module.h> 12080b47deSLogan Gunthorpe #include <linux/fs.h> 13080b47deSLogan Gunthorpe #include <linux/uaccess.h> 14080b47deSLogan Gunthorpe #include <linux/poll.h> 15080b47deSLogan Gunthorpe #include <linux/wait.h> 16f7eb7b8aSWesley Sheng #include <linux/io-64-nonatomic-lo-hi.h> 1746feb6b4SGustavo A. R. Silva #include <linux/nospec.h> 1846feb6b4SGustavo A. R. Silva 19080b47deSLogan Gunthorpe MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver"); 20080b47deSLogan Gunthorpe MODULE_VERSION("0.1"); 21080b47deSLogan Gunthorpe MODULE_LICENSE("GPL"); 22080b47deSLogan Gunthorpe MODULE_AUTHOR("Microsemi Corporation"); 23080b47deSLogan Gunthorpe 24080b47deSLogan Gunthorpe static int max_devices = 16; 25080b47deSLogan Gunthorpe module_param(max_devices, int, 0644); 26080b47deSLogan Gunthorpe MODULE_PARM_DESC(max_devices, "max number of switchtec device instances"); 27080b47deSLogan Gunthorpe 28*b8af8549SKrzysztof Wilczynski static bool use_dma_mrpc = true; 29f7eb7b8aSWesley Sheng module_param(use_dma_mrpc, bool, 0644); 30f7eb7b8aSWesley Sheng MODULE_PARM_DESC(use_dma_mrpc, 31f7eb7b8aSWesley Sheng "Enable the use of the DMA MRPC feature"); 32f7eb7b8aSWesley Sheng 33fcdf8e95SLogan Gunthorpe static int nirqs = 32; 34fcdf8e95SLogan Gunthorpe module_param(nirqs, int, 0644); 35fcdf8e95SLogan Gunthorpe MODULE_PARM_DESC(nirqs, "number of interrupts to allocate (more may be useful for NTB applications)"); 36fcdf8e95SLogan Gunthorpe 37080b47deSLogan Gunthorpe static dev_t switchtec_devt; 38080b47deSLogan Gunthorpe static DEFINE_IDA(switchtec_minor_ida); 39080b47deSLogan Gunthorpe 40302e994dSLogan Gunthorpe struct class *switchtec_class; 41302e994dSLogan Gunthorpe EXPORT_SYMBOL_GPL(switchtec_class); 42080b47deSLogan Gunthorpe 43080b47deSLogan Gunthorpe enum mrpc_state { 44080b47deSLogan Gunthorpe MRPC_IDLE = 0, 45080b47deSLogan Gunthorpe MRPC_QUEUED, 46080b47deSLogan Gunthorpe MRPC_RUNNING, 47080b47deSLogan Gunthorpe MRPC_DONE, 48080b47deSLogan Gunthorpe }; 49080b47deSLogan Gunthorpe 50080b47deSLogan Gunthorpe struct switchtec_user { 51080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 52080b47deSLogan Gunthorpe 53080b47deSLogan Gunthorpe enum mrpc_state state; 54080b47deSLogan Gunthorpe 55deaa0a8aSSebastian Andrzej Siewior wait_queue_head_t cmd_comp; 56080b47deSLogan Gunthorpe struct kref kref; 57080b47deSLogan Gunthorpe struct list_head list; 58080b47deSLogan Gunthorpe 59deaa0a8aSSebastian Andrzej Siewior bool cmd_done; 60080b47deSLogan Gunthorpe u32 cmd; 61080b47deSLogan Gunthorpe u32 status; 62080b47deSLogan Gunthorpe u32 return_code; 63080b47deSLogan Gunthorpe size_t data_len; 64080b47deSLogan Gunthorpe size_t read_len; 65080b47deSLogan Gunthorpe unsigned char data[SWITCHTEC_MRPC_PAYLOAD_SIZE]; 66080b47deSLogan Gunthorpe int event_cnt; 67080b47deSLogan Gunthorpe }; 68080b47deSLogan Gunthorpe 69080b47deSLogan Gunthorpe static struct switchtec_user *stuser_create(struct switchtec_dev *stdev) 70080b47deSLogan Gunthorpe { 71080b47deSLogan Gunthorpe struct switchtec_user *stuser; 72080b47deSLogan Gunthorpe 73080b47deSLogan Gunthorpe stuser = kzalloc(sizeof(*stuser), GFP_KERNEL); 74080b47deSLogan Gunthorpe if (!stuser) 75080b47deSLogan Gunthorpe return ERR_PTR(-ENOMEM); 76080b47deSLogan Gunthorpe 77080b47deSLogan Gunthorpe get_device(&stdev->dev); 78080b47deSLogan Gunthorpe stuser->stdev = stdev; 79080b47deSLogan Gunthorpe kref_init(&stuser->kref); 80080b47deSLogan Gunthorpe INIT_LIST_HEAD(&stuser->list); 81deaa0a8aSSebastian Andrzej Siewior init_waitqueue_head(&stuser->cmd_comp); 82080b47deSLogan Gunthorpe stuser->event_cnt = atomic_read(&stdev->event_cnt); 83080b47deSLogan Gunthorpe 84080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser); 85080b47deSLogan Gunthorpe 86080b47deSLogan Gunthorpe return stuser; 87080b47deSLogan Gunthorpe } 88080b47deSLogan Gunthorpe 89080b47deSLogan Gunthorpe static void stuser_free(struct kref *kref) 90080b47deSLogan Gunthorpe { 91080b47deSLogan Gunthorpe struct switchtec_user *stuser; 92080b47deSLogan Gunthorpe 93080b47deSLogan Gunthorpe stuser = container_of(kref, struct switchtec_user, kref); 94080b47deSLogan Gunthorpe 95080b47deSLogan Gunthorpe dev_dbg(&stuser->stdev->dev, "%s: %p\n", __func__, stuser); 96080b47deSLogan Gunthorpe 97080b47deSLogan Gunthorpe put_device(&stuser->stdev->dev); 98080b47deSLogan Gunthorpe kfree(stuser); 99080b47deSLogan Gunthorpe } 100080b47deSLogan Gunthorpe 101080b47deSLogan Gunthorpe static void stuser_put(struct switchtec_user *stuser) 102080b47deSLogan Gunthorpe { 103080b47deSLogan Gunthorpe kref_put(&stuser->kref, stuser_free); 104080b47deSLogan Gunthorpe } 105080b47deSLogan Gunthorpe 106080b47deSLogan Gunthorpe static void stuser_set_state(struct switchtec_user *stuser, 107080b47deSLogan Gunthorpe enum mrpc_state state) 108080b47deSLogan Gunthorpe { 109080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 110080b47deSLogan Gunthorpe 111080b47deSLogan Gunthorpe const char * const state_names[] = { 112080b47deSLogan Gunthorpe [MRPC_IDLE] = "IDLE", 113080b47deSLogan Gunthorpe [MRPC_QUEUED] = "QUEUED", 114080b47deSLogan Gunthorpe [MRPC_RUNNING] = "RUNNING", 115080b47deSLogan Gunthorpe [MRPC_DONE] = "DONE", 116080b47deSLogan Gunthorpe }; 117080b47deSLogan Gunthorpe 118080b47deSLogan Gunthorpe stuser->state = state; 119080b47deSLogan Gunthorpe 120080b47deSLogan Gunthorpe dev_dbg(&stuser->stdev->dev, "stuser state %p -> %s", 121080b47deSLogan Gunthorpe stuser, state_names[state]); 122080b47deSLogan Gunthorpe } 123080b47deSLogan Gunthorpe 124080b47deSLogan Gunthorpe static void mrpc_complete_cmd(struct switchtec_dev *stdev); 125080b47deSLogan Gunthorpe 12652d8db8eSKelvin Cao static void flush_wc_buf(struct switchtec_dev *stdev) 12752d8db8eSKelvin Cao { 12852d8db8eSKelvin Cao struct ntb_dbmsg_regs __iomem *mmio_dbmsg; 12952d8db8eSKelvin Cao 13052d8db8eSKelvin Cao /* 13152d8db8eSKelvin Cao * odb (outbound doorbell) register is processed by low latency 13252d8db8eSKelvin Cao * hardware and w/o side effect 13352d8db8eSKelvin Cao */ 13452d8db8eSKelvin Cao mmio_dbmsg = (void __iomem *)stdev->mmio_ntb + 13552d8db8eSKelvin Cao SWITCHTEC_NTB_REG_DBMSG_OFFSET; 13652d8db8eSKelvin Cao ioread32(&mmio_dbmsg->odb); 13752d8db8eSKelvin Cao } 13852d8db8eSKelvin Cao 139080b47deSLogan Gunthorpe static void mrpc_cmd_submit(struct switchtec_dev *stdev) 140080b47deSLogan Gunthorpe { 141080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 142080b47deSLogan Gunthorpe 143080b47deSLogan Gunthorpe struct switchtec_user *stuser; 144080b47deSLogan Gunthorpe 145080b47deSLogan Gunthorpe if (stdev->mrpc_busy) 146080b47deSLogan Gunthorpe return; 147080b47deSLogan Gunthorpe 148080b47deSLogan Gunthorpe if (list_empty(&stdev->mrpc_queue)) 149080b47deSLogan Gunthorpe return; 150080b47deSLogan Gunthorpe 151080b47deSLogan Gunthorpe stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, 152080b47deSLogan Gunthorpe list); 153080b47deSLogan Gunthorpe 154f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) { 155f7eb7b8aSWesley Sheng stdev->dma_mrpc->status = SWITCHTEC_MRPC_STATUS_INPROGRESS; 156f7eb7b8aSWesley Sheng memset(stdev->dma_mrpc->data, 0xFF, SWITCHTEC_MRPC_PAYLOAD_SIZE); 157f7eb7b8aSWesley Sheng } 158f7eb7b8aSWesley Sheng 159080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_RUNNING); 160080b47deSLogan Gunthorpe stdev->mrpc_busy = 1; 161080b47deSLogan Gunthorpe memcpy_toio(&stdev->mmio_mrpc->input_data, 162080b47deSLogan Gunthorpe stuser->data, stuser->data_len); 16352d8db8eSKelvin Cao flush_wc_buf(stdev); 164080b47deSLogan Gunthorpe iowrite32(stuser->cmd, &stdev->mmio_mrpc->cmd); 165080b47deSLogan Gunthorpe 166080b47deSLogan Gunthorpe schedule_delayed_work(&stdev->mrpc_timeout, 167080b47deSLogan Gunthorpe msecs_to_jiffies(500)); 168080b47deSLogan Gunthorpe } 169080b47deSLogan Gunthorpe 170080b47deSLogan Gunthorpe static int mrpc_queue_cmd(struct switchtec_user *stuser) 171080b47deSLogan Gunthorpe { 172080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 173080b47deSLogan Gunthorpe 174080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 175080b47deSLogan Gunthorpe 176080b47deSLogan Gunthorpe kref_get(&stuser->kref); 177080b47deSLogan Gunthorpe stuser->read_len = sizeof(stuser->data); 178080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_QUEUED); 179deaa0a8aSSebastian Andrzej Siewior stuser->cmd_done = false; 180080b47deSLogan Gunthorpe list_add_tail(&stuser->list, &stdev->mrpc_queue); 181080b47deSLogan Gunthorpe 182080b47deSLogan Gunthorpe mrpc_cmd_submit(stdev); 183080b47deSLogan Gunthorpe 184080b47deSLogan Gunthorpe return 0; 185080b47deSLogan Gunthorpe } 186080b47deSLogan Gunthorpe 187080b47deSLogan Gunthorpe static void mrpc_complete_cmd(struct switchtec_dev *stdev) 188080b47deSLogan Gunthorpe { 189080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 190080b47deSLogan Gunthorpe struct switchtec_user *stuser; 191080b47deSLogan Gunthorpe 192080b47deSLogan Gunthorpe if (list_empty(&stdev->mrpc_queue)) 193080b47deSLogan Gunthorpe return; 194080b47deSLogan Gunthorpe 195080b47deSLogan Gunthorpe stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, 196080b47deSLogan Gunthorpe list); 197080b47deSLogan Gunthorpe 198f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) 199f7eb7b8aSWesley Sheng stuser->status = stdev->dma_mrpc->status; 200f7eb7b8aSWesley Sheng else 201080b47deSLogan Gunthorpe stuser->status = ioread32(&stdev->mmio_mrpc->status); 202f7eb7b8aSWesley Sheng 203080b47deSLogan Gunthorpe if (stuser->status == SWITCHTEC_MRPC_STATUS_INPROGRESS) 204080b47deSLogan Gunthorpe return; 205080b47deSLogan Gunthorpe 206080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_DONE); 207080b47deSLogan Gunthorpe stuser->return_code = 0; 208080b47deSLogan Gunthorpe 209080b47deSLogan Gunthorpe if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE) 210080b47deSLogan Gunthorpe goto out; 211080b47deSLogan Gunthorpe 212f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) 213f7eb7b8aSWesley Sheng stuser->return_code = stdev->dma_mrpc->rtn_code; 214f7eb7b8aSWesley Sheng else 215080b47deSLogan Gunthorpe stuser->return_code = ioread32(&stdev->mmio_mrpc->ret_value); 216080b47deSLogan Gunthorpe if (stuser->return_code != 0) 217080b47deSLogan Gunthorpe goto out; 218080b47deSLogan Gunthorpe 219f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) 220f7eb7b8aSWesley Sheng memcpy(stuser->data, &stdev->dma_mrpc->data, 221f7eb7b8aSWesley Sheng stuser->read_len); 222f7eb7b8aSWesley Sheng else 223080b47deSLogan Gunthorpe memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data, 224080b47deSLogan Gunthorpe stuser->read_len); 225080b47deSLogan Gunthorpe out: 226deaa0a8aSSebastian Andrzej Siewior stuser->cmd_done = true; 227deaa0a8aSSebastian Andrzej Siewior wake_up_interruptible(&stuser->cmd_comp); 228080b47deSLogan Gunthorpe list_del_init(&stuser->list); 229080b47deSLogan Gunthorpe stuser_put(stuser); 230080b47deSLogan Gunthorpe stdev->mrpc_busy = 0; 231080b47deSLogan Gunthorpe 232080b47deSLogan Gunthorpe mrpc_cmd_submit(stdev); 233080b47deSLogan Gunthorpe } 234080b47deSLogan Gunthorpe 235080b47deSLogan Gunthorpe static void mrpc_event_work(struct work_struct *work) 236080b47deSLogan Gunthorpe { 237080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 238080b47deSLogan Gunthorpe 239080b47deSLogan Gunthorpe stdev = container_of(work, struct switchtec_dev, mrpc_work); 240080b47deSLogan Gunthorpe 241080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s\n", __func__); 242080b47deSLogan Gunthorpe 243080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 244080b47deSLogan Gunthorpe cancel_delayed_work(&stdev->mrpc_timeout); 245080b47deSLogan Gunthorpe mrpc_complete_cmd(stdev); 246080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 247080b47deSLogan Gunthorpe } 248080b47deSLogan Gunthorpe 249080b47deSLogan Gunthorpe static void mrpc_timeout_work(struct work_struct *work) 250080b47deSLogan Gunthorpe { 251080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 252080b47deSLogan Gunthorpe u32 status; 253080b47deSLogan Gunthorpe 254080b47deSLogan Gunthorpe stdev = container_of(work, struct switchtec_dev, mrpc_timeout.work); 255080b47deSLogan Gunthorpe 256080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s\n", __func__); 257080b47deSLogan Gunthorpe 258080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 259080b47deSLogan Gunthorpe 260f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) 261f7eb7b8aSWesley Sheng status = stdev->dma_mrpc->status; 262f7eb7b8aSWesley Sheng else 263080b47deSLogan Gunthorpe status = ioread32(&stdev->mmio_mrpc->status); 264080b47deSLogan Gunthorpe if (status == SWITCHTEC_MRPC_STATUS_INPROGRESS) { 265080b47deSLogan Gunthorpe schedule_delayed_work(&stdev->mrpc_timeout, 266080b47deSLogan Gunthorpe msecs_to_jiffies(500)); 267080b47deSLogan Gunthorpe goto out; 268080b47deSLogan Gunthorpe } 269080b47deSLogan Gunthorpe 270080b47deSLogan Gunthorpe mrpc_complete_cmd(stdev); 271080b47deSLogan Gunthorpe out: 272080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 273080b47deSLogan Gunthorpe } 274080b47deSLogan Gunthorpe 2755d8e1881SLogan Gunthorpe static ssize_t device_version_show(struct device *dev, 2765d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 2775d8e1881SLogan Gunthorpe { 2785d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 2795d8e1881SLogan Gunthorpe u32 ver; 2805d8e1881SLogan Gunthorpe 2815d8e1881SLogan Gunthorpe ver = ioread32(&stdev->mmio_sys_info->device_version); 2825d8e1881SLogan Gunthorpe 2835d8e1881SLogan Gunthorpe return sprintf(buf, "%x\n", ver); 2845d8e1881SLogan Gunthorpe } 2855d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(device_version); 2865d8e1881SLogan Gunthorpe 2875d8e1881SLogan Gunthorpe static ssize_t fw_version_show(struct device *dev, 2885d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 2895d8e1881SLogan Gunthorpe { 2905d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 2915d8e1881SLogan Gunthorpe u32 ver; 2925d8e1881SLogan Gunthorpe 2935d8e1881SLogan Gunthorpe ver = ioread32(&stdev->mmio_sys_info->firmware_version); 2945d8e1881SLogan Gunthorpe 2955d8e1881SLogan Gunthorpe return sprintf(buf, "%08x\n", ver); 2965d8e1881SLogan Gunthorpe } 2975d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(fw_version); 2985d8e1881SLogan Gunthorpe 2995d8e1881SLogan Gunthorpe static ssize_t io_string_show(char *buf, void __iomem *attr, size_t len) 3005d8e1881SLogan Gunthorpe { 3015d8e1881SLogan Gunthorpe int i; 3025d8e1881SLogan Gunthorpe 3035d8e1881SLogan Gunthorpe memcpy_fromio(buf, attr, len); 3045d8e1881SLogan Gunthorpe buf[len] = '\n'; 3055d8e1881SLogan Gunthorpe buf[len + 1] = 0; 3065d8e1881SLogan Gunthorpe 3075d8e1881SLogan Gunthorpe for (i = len - 1; i > 0; i--) { 3085d8e1881SLogan Gunthorpe if (buf[i] != ' ') 3095d8e1881SLogan Gunthorpe break; 3105d8e1881SLogan Gunthorpe buf[i] = '\n'; 3115d8e1881SLogan Gunthorpe buf[i + 1] = 0; 3125d8e1881SLogan Gunthorpe } 3135d8e1881SLogan Gunthorpe 3145d8e1881SLogan Gunthorpe return strlen(buf); 3155d8e1881SLogan Gunthorpe } 3165d8e1881SLogan Gunthorpe 3175d8e1881SLogan Gunthorpe #define DEVICE_ATTR_SYS_INFO_STR(field) \ 3185d8e1881SLogan Gunthorpe static ssize_t field ## _show(struct device *dev, \ 3195d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) \ 3205d8e1881SLogan Gunthorpe { \ 3215d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); \ 322993d208dSLogan Gunthorpe struct sys_info_regs __iomem *si = stdev->mmio_sys_info; \ 323993d208dSLogan Gunthorpe if (stdev->gen == SWITCHTEC_GEN3) \ 324993d208dSLogan Gunthorpe return io_string_show(buf, &si->gen3.field, \ 325993d208dSLogan Gunthorpe sizeof(si->gen3.field)); \ 326a3321ca3SLogan Gunthorpe else if (stdev->gen == SWITCHTEC_GEN4) \ 327a3321ca3SLogan Gunthorpe return io_string_show(buf, &si->gen4.field, \ 328a3321ca3SLogan Gunthorpe sizeof(si->gen4.field)); \ 329993d208dSLogan Gunthorpe else \ 330993d208dSLogan Gunthorpe return -ENOTSUPP; \ 3315d8e1881SLogan Gunthorpe } \ 3325d8e1881SLogan Gunthorpe \ 3335d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(field) 3345d8e1881SLogan Gunthorpe 3355d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(vendor_id); 3365d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(product_id); 3375d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(product_revision); 338b13313a0SLogan Gunthorpe 339b13313a0SLogan Gunthorpe static ssize_t component_vendor_show(struct device *dev, 340b13313a0SLogan Gunthorpe struct device_attribute *attr, char *buf) 341b13313a0SLogan Gunthorpe { 342b13313a0SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 343b13313a0SLogan Gunthorpe struct sys_info_regs __iomem *si = stdev->mmio_sys_info; 344b13313a0SLogan Gunthorpe 345b13313a0SLogan Gunthorpe /* component_vendor field not supported after gen3 */ 346b13313a0SLogan Gunthorpe if (stdev->gen != SWITCHTEC_GEN3) 347b13313a0SLogan Gunthorpe return sprintf(buf, "none\n"); 348b13313a0SLogan Gunthorpe 349993d208dSLogan Gunthorpe return io_string_show(buf, &si->gen3.component_vendor, 350993d208dSLogan Gunthorpe sizeof(si->gen3.component_vendor)); 351b13313a0SLogan Gunthorpe } 352b13313a0SLogan Gunthorpe static DEVICE_ATTR_RO(component_vendor); 3535d8e1881SLogan Gunthorpe 3545d8e1881SLogan Gunthorpe static ssize_t component_id_show(struct device *dev, 3555d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 3565d8e1881SLogan Gunthorpe { 3575d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 358993d208dSLogan Gunthorpe int id = ioread16(&stdev->mmio_sys_info->gen3.component_id); 3595d8e1881SLogan Gunthorpe 360b13313a0SLogan Gunthorpe /* component_id field not supported after gen3 */ 361b13313a0SLogan Gunthorpe if (stdev->gen != SWITCHTEC_GEN3) 362b13313a0SLogan Gunthorpe return sprintf(buf, "none\n"); 363b13313a0SLogan Gunthorpe 3645d8e1881SLogan Gunthorpe return sprintf(buf, "PM%04X\n", id); 3655d8e1881SLogan Gunthorpe } 3665d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(component_id); 3675d8e1881SLogan Gunthorpe 3685d8e1881SLogan Gunthorpe static ssize_t component_revision_show(struct device *dev, 3695d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 3705d8e1881SLogan Gunthorpe { 3715d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 372993d208dSLogan Gunthorpe int rev = ioread8(&stdev->mmio_sys_info->gen3.component_revision); 3735d8e1881SLogan Gunthorpe 374b13313a0SLogan Gunthorpe /* component_revision field not supported after gen3 */ 375b13313a0SLogan Gunthorpe if (stdev->gen != SWITCHTEC_GEN3) 376b13313a0SLogan Gunthorpe return sprintf(buf, "255\n"); 377b13313a0SLogan Gunthorpe 3785d8e1881SLogan Gunthorpe return sprintf(buf, "%d\n", rev); 3795d8e1881SLogan Gunthorpe } 3805d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(component_revision); 3815d8e1881SLogan Gunthorpe 3825d8e1881SLogan Gunthorpe static ssize_t partition_show(struct device *dev, 3835d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 3845d8e1881SLogan Gunthorpe { 3855d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 3865d8e1881SLogan Gunthorpe 3875d8e1881SLogan Gunthorpe return sprintf(buf, "%d\n", stdev->partition); 3885d8e1881SLogan Gunthorpe } 3895d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(partition); 3905d8e1881SLogan Gunthorpe 3915d8e1881SLogan Gunthorpe static ssize_t partition_count_show(struct device *dev, 3925d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 3935d8e1881SLogan Gunthorpe { 3945d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 3955d8e1881SLogan Gunthorpe 3965d8e1881SLogan Gunthorpe return sprintf(buf, "%d\n", stdev->partition_count); 3975d8e1881SLogan Gunthorpe } 3985d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(partition_count); 3995d8e1881SLogan Gunthorpe 4005d8e1881SLogan Gunthorpe static struct attribute *switchtec_device_attrs[] = { 4015d8e1881SLogan Gunthorpe &dev_attr_device_version.attr, 4025d8e1881SLogan Gunthorpe &dev_attr_fw_version.attr, 4035d8e1881SLogan Gunthorpe &dev_attr_vendor_id.attr, 4045d8e1881SLogan Gunthorpe &dev_attr_product_id.attr, 4055d8e1881SLogan Gunthorpe &dev_attr_product_revision.attr, 4065d8e1881SLogan Gunthorpe &dev_attr_component_vendor.attr, 4075d8e1881SLogan Gunthorpe &dev_attr_component_id.attr, 4085d8e1881SLogan Gunthorpe &dev_attr_component_revision.attr, 4095d8e1881SLogan Gunthorpe &dev_attr_partition.attr, 4105d8e1881SLogan Gunthorpe &dev_attr_partition_count.attr, 4115d8e1881SLogan Gunthorpe NULL, 4125d8e1881SLogan Gunthorpe }; 4135d8e1881SLogan Gunthorpe 4145d8e1881SLogan Gunthorpe ATTRIBUTE_GROUPS(switchtec_device); 4155d8e1881SLogan Gunthorpe 416080b47deSLogan Gunthorpe static int switchtec_dev_open(struct inode *inode, struct file *filp) 417080b47deSLogan Gunthorpe { 418080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 419080b47deSLogan Gunthorpe struct switchtec_user *stuser; 420080b47deSLogan Gunthorpe 421080b47deSLogan Gunthorpe stdev = container_of(inode->i_cdev, struct switchtec_dev, cdev); 422080b47deSLogan Gunthorpe 423080b47deSLogan Gunthorpe stuser = stuser_create(stdev); 424080b47deSLogan Gunthorpe if (IS_ERR(stuser)) 425080b47deSLogan Gunthorpe return PTR_ERR(stuser); 426080b47deSLogan Gunthorpe 427080b47deSLogan Gunthorpe filp->private_data = stuser; 428c5bf68feSKirill Smelkov stream_open(inode, filp); 429080b47deSLogan Gunthorpe 430080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser); 431080b47deSLogan Gunthorpe 432080b47deSLogan Gunthorpe return 0; 433080b47deSLogan Gunthorpe } 434080b47deSLogan Gunthorpe 435080b47deSLogan Gunthorpe static int switchtec_dev_release(struct inode *inode, struct file *filp) 436080b47deSLogan Gunthorpe { 437080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 438080b47deSLogan Gunthorpe 439080b47deSLogan Gunthorpe stuser_put(stuser); 440080b47deSLogan Gunthorpe 441080b47deSLogan Gunthorpe return 0; 442080b47deSLogan Gunthorpe } 443080b47deSLogan Gunthorpe 444080b47deSLogan Gunthorpe static int lock_mutex_and_test_alive(struct switchtec_dev *stdev) 445080b47deSLogan Gunthorpe { 446080b47deSLogan Gunthorpe if (mutex_lock_interruptible(&stdev->mrpc_mutex)) 447080b47deSLogan Gunthorpe return -EINTR; 448080b47deSLogan Gunthorpe 449080b47deSLogan Gunthorpe if (!stdev->alive) { 450080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 451080b47deSLogan Gunthorpe return -ENODEV; 452080b47deSLogan Gunthorpe } 453080b47deSLogan Gunthorpe 454080b47deSLogan Gunthorpe return 0; 455080b47deSLogan Gunthorpe } 456080b47deSLogan Gunthorpe 457080b47deSLogan Gunthorpe static ssize_t switchtec_dev_write(struct file *filp, const char __user *data, 458080b47deSLogan Gunthorpe size_t size, loff_t *off) 459080b47deSLogan Gunthorpe { 460080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 461080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 462080b47deSLogan Gunthorpe int rc; 463080b47deSLogan Gunthorpe 464080b47deSLogan Gunthorpe if (size < sizeof(stuser->cmd) || 465080b47deSLogan Gunthorpe size > sizeof(stuser->cmd) + sizeof(stuser->data)) 466080b47deSLogan Gunthorpe return -EINVAL; 467080b47deSLogan Gunthorpe 468080b47deSLogan Gunthorpe stuser->data_len = size - sizeof(stuser->cmd); 469080b47deSLogan Gunthorpe 470080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 471080b47deSLogan Gunthorpe if (rc) 472080b47deSLogan Gunthorpe return rc; 473080b47deSLogan Gunthorpe 474080b47deSLogan Gunthorpe if (stuser->state != MRPC_IDLE) { 475080b47deSLogan Gunthorpe rc = -EBADE; 476080b47deSLogan Gunthorpe goto out; 477080b47deSLogan Gunthorpe } 478080b47deSLogan Gunthorpe 479080b47deSLogan Gunthorpe rc = copy_from_user(&stuser->cmd, data, sizeof(stuser->cmd)); 480080b47deSLogan Gunthorpe if (rc) { 481080b47deSLogan Gunthorpe rc = -EFAULT; 482080b47deSLogan Gunthorpe goto out; 483080b47deSLogan Gunthorpe } 484ce7c8860SKelvin Cao if (((MRPC_CMD_ID(stuser->cmd) == MRPC_GAS_WRITE) || 485ce7c8860SKelvin Cao (MRPC_CMD_ID(stuser->cmd) == MRPC_GAS_READ)) && 486ce7c8860SKelvin Cao !capable(CAP_SYS_ADMIN)) { 487ce7c8860SKelvin Cao rc = -EPERM; 488ce7c8860SKelvin Cao goto out; 489ce7c8860SKelvin Cao } 490080b47deSLogan Gunthorpe 491080b47deSLogan Gunthorpe data += sizeof(stuser->cmd); 492080b47deSLogan Gunthorpe rc = copy_from_user(&stuser->data, data, size - sizeof(stuser->cmd)); 493080b47deSLogan Gunthorpe if (rc) { 494080b47deSLogan Gunthorpe rc = -EFAULT; 495080b47deSLogan Gunthorpe goto out; 496080b47deSLogan Gunthorpe } 497080b47deSLogan Gunthorpe 498080b47deSLogan Gunthorpe rc = mrpc_queue_cmd(stuser); 499080b47deSLogan Gunthorpe 500080b47deSLogan Gunthorpe out: 501080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 502080b47deSLogan Gunthorpe 503080b47deSLogan Gunthorpe if (rc) 504080b47deSLogan Gunthorpe return rc; 505080b47deSLogan Gunthorpe 506080b47deSLogan Gunthorpe return size; 507080b47deSLogan Gunthorpe } 508080b47deSLogan Gunthorpe 509080b47deSLogan Gunthorpe static ssize_t switchtec_dev_read(struct file *filp, char __user *data, 510080b47deSLogan Gunthorpe size_t size, loff_t *off) 511080b47deSLogan Gunthorpe { 512080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 513080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 514080b47deSLogan Gunthorpe int rc; 515080b47deSLogan Gunthorpe 516080b47deSLogan Gunthorpe if (size < sizeof(stuser->cmd) || 517080b47deSLogan Gunthorpe size > sizeof(stuser->cmd) + sizeof(stuser->data)) 518080b47deSLogan Gunthorpe return -EINVAL; 519080b47deSLogan Gunthorpe 520080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 521080b47deSLogan Gunthorpe if (rc) 522080b47deSLogan Gunthorpe return rc; 523080b47deSLogan Gunthorpe 524080b47deSLogan Gunthorpe if (stuser->state == MRPC_IDLE) { 525080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 526080b47deSLogan Gunthorpe return -EBADE; 527080b47deSLogan Gunthorpe } 528080b47deSLogan Gunthorpe 529080b47deSLogan Gunthorpe stuser->read_len = size - sizeof(stuser->return_code); 530080b47deSLogan Gunthorpe 531080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 532080b47deSLogan Gunthorpe 533080b47deSLogan Gunthorpe if (filp->f_flags & O_NONBLOCK) { 534deaa0a8aSSebastian Andrzej Siewior if (!stuser->cmd_done) 535080b47deSLogan Gunthorpe return -EAGAIN; 536080b47deSLogan Gunthorpe } else { 537deaa0a8aSSebastian Andrzej Siewior rc = wait_event_interruptible(stuser->cmd_comp, 538deaa0a8aSSebastian Andrzej Siewior stuser->cmd_done); 539080b47deSLogan Gunthorpe if (rc < 0) 540080b47deSLogan Gunthorpe return rc; 541080b47deSLogan Gunthorpe } 542080b47deSLogan Gunthorpe 543080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 544080b47deSLogan Gunthorpe if (rc) 545080b47deSLogan Gunthorpe return rc; 546080b47deSLogan Gunthorpe 547080b47deSLogan Gunthorpe if (stuser->state != MRPC_DONE) { 548080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 549080b47deSLogan Gunthorpe return -EBADE; 550080b47deSLogan Gunthorpe } 551080b47deSLogan Gunthorpe 552080b47deSLogan Gunthorpe rc = copy_to_user(data, &stuser->return_code, 553080b47deSLogan Gunthorpe sizeof(stuser->return_code)); 554080b47deSLogan Gunthorpe if (rc) { 555080b47deSLogan Gunthorpe rc = -EFAULT; 556080b47deSLogan Gunthorpe goto out; 557080b47deSLogan Gunthorpe } 558080b47deSLogan Gunthorpe 559080b47deSLogan Gunthorpe data += sizeof(stuser->return_code); 560080b47deSLogan Gunthorpe rc = copy_to_user(data, &stuser->data, 561080b47deSLogan Gunthorpe size - sizeof(stuser->return_code)); 562080b47deSLogan Gunthorpe if (rc) { 563080b47deSLogan Gunthorpe rc = -EFAULT; 564080b47deSLogan Gunthorpe goto out; 565080b47deSLogan Gunthorpe } 566080b47deSLogan Gunthorpe 567080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_IDLE); 568080b47deSLogan Gunthorpe 569080b47deSLogan Gunthorpe out: 570080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 571080b47deSLogan Gunthorpe 572080b47deSLogan Gunthorpe if (stuser->status == SWITCHTEC_MRPC_STATUS_DONE) 573080b47deSLogan Gunthorpe return size; 574080b47deSLogan Gunthorpe else if (stuser->status == SWITCHTEC_MRPC_STATUS_INTERRUPTED) 575080b47deSLogan Gunthorpe return -ENXIO; 576080b47deSLogan Gunthorpe else 577080b47deSLogan Gunthorpe return -EBADMSG; 578080b47deSLogan Gunthorpe } 579080b47deSLogan Gunthorpe 580afc9a42bSAl Viro static __poll_t switchtec_dev_poll(struct file *filp, poll_table *wait) 581080b47deSLogan Gunthorpe { 582080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 583080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 584afc9a42bSAl Viro __poll_t ret = 0; 585080b47deSLogan Gunthorpe 586deaa0a8aSSebastian Andrzej Siewior poll_wait(filp, &stuser->cmd_comp, wait); 587080b47deSLogan Gunthorpe poll_wait(filp, &stdev->event_wq, wait); 588080b47deSLogan Gunthorpe 589080b47deSLogan Gunthorpe if (lock_mutex_and_test_alive(stdev)) 590a9a08845SLinus Torvalds return EPOLLIN | EPOLLRDHUP | EPOLLOUT | EPOLLERR | EPOLLHUP; 591080b47deSLogan Gunthorpe 592080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 593080b47deSLogan Gunthorpe 594deaa0a8aSSebastian Andrzej Siewior if (stuser->cmd_done) 595a9a08845SLinus Torvalds ret |= EPOLLIN | EPOLLRDNORM; 596080b47deSLogan Gunthorpe 597080b47deSLogan Gunthorpe if (stuser->event_cnt != atomic_read(&stdev->event_cnt)) 598a9a08845SLinus Torvalds ret |= EPOLLPRI | EPOLLRDBAND; 599080b47deSLogan Gunthorpe 600080b47deSLogan Gunthorpe return ret; 601080b47deSLogan Gunthorpe } 602080b47deSLogan Gunthorpe 60352eabba5SLogan Gunthorpe static int ioctl_flash_info(struct switchtec_dev *stdev, 60452eabba5SLogan Gunthorpe struct switchtec_ioctl_flash_info __user *uinfo) 60552eabba5SLogan Gunthorpe { 60652eabba5SLogan Gunthorpe struct switchtec_ioctl_flash_info info = {0}; 60752eabba5SLogan Gunthorpe struct flash_info_regs __iomem *fi = stdev->mmio_flash_info; 60852eabba5SLogan Gunthorpe 609993d208dSLogan Gunthorpe if (stdev->gen == SWITCHTEC_GEN3) { 610993d208dSLogan Gunthorpe info.flash_length = ioread32(&fi->gen3.flash_length); 611fcccd282SLogan Gunthorpe info.num_partitions = SWITCHTEC_NUM_PARTITIONS_GEN3; 6124efa1d2eSKelvin Cao } else if (stdev->gen == SWITCHTEC_GEN4) { 6134efa1d2eSKelvin Cao info.flash_length = ioread32(&fi->gen4.flash_length); 6144efa1d2eSKelvin Cao info.num_partitions = SWITCHTEC_NUM_PARTITIONS_GEN4; 615993d208dSLogan Gunthorpe } else { 616993d208dSLogan Gunthorpe return -ENOTSUPP; 617993d208dSLogan Gunthorpe } 61852eabba5SLogan Gunthorpe 61952eabba5SLogan Gunthorpe if (copy_to_user(uinfo, &info, sizeof(info))) 62052eabba5SLogan Gunthorpe return -EFAULT; 62152eabba5SLogan Gunthorpe 62252eabba5SLogan Gunthorpe return 0; 62352eabba5SLogan Gunthorpe } 62452eabba5SLogan Gunthorpe 62552eabba5SLogan Gunthorpe static void set_fw_info_part(struct switchtec_ioctl_flash_part_info *info, 62652eabba5SLogan Gunthorpe struct partition_info __iomem *pi) 62752eabba5SLogan Gunthorpe { 62852eabba5SLogan Gunthorpe info->address = ioread32(&pi->address); 62952eabba5SLogan Gunthorpe info->length = ioread32(&pi->length); 63052eabba5SLogan Gunthorpe } 63152eabba5SLogan Gunthorpe 6326a3d1b54SLogan Gunthorpe static int flash_part_info_gen3(struct switchtec_dev *stdev, 6336a3d1b54SLogan Gunthorpe struct switchtec_ioctl_flash_part_info *info) 63452eabba5SLogan Gunthorpe { 635993d208dSLogan Gunthorpe struct flash_info_regs_gen3 __iomem *fi = 636993d208dSLogan Gunthorpe &stdev->mmio_flash_info->gen3; 637993d208dSLogan Gunthorpe struct sys_info_regs_gen3 __iomem *si = &stdev->mmio_sys_info->gen3; 63852eabba5SLogan Gunthorpe u32 active_addr = -1; 63952eabba5SLogan Gunthorpe 6406a3d1b54SLogan Gunthorpe switch (info->flash_partition) { 64152eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_CFG0: 64252eabba5SLogan Gunthorpe active_addr = ioread32(&fi->active_cfg); 6436a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->cfg0); 644fcccd282SLogan Gunthorpe if (ioread16(&si->cfg_running) == SWITCHTEC_GEN3_CFG0_RUNNING) 6456a3d1b54SLogan Gunthorpe info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 64652eabba5SLogan Gunthorpe break; 64752eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_CFG1: 64852eabba5SLogan Gunthorpe active_addr = ioread32(&fi->active_cfg); 6496a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->cfg1); 650fcccd282SLogan Gunthorpe if (ioread16(&si->cfg_running) == SWITCHTEC_GEN3_CFG1_RUNNING) 6516a3d1b54SLogan Gunthorpe info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 65252eabba5SLogan Gunthorpe break; 65352eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_IMG0: 65452eabba5SLogan Gunthorpe active_addr = ioread32(&fi->active_img); 6556a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->img0); 656fcccd282SLogan Gunthorpe if (ioread16(&si->img_running) == SWITCHTEC_GEN3_IMG0_RUNNING) 6576a3d1b54SLogan Gunthorpe info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 65852eabba5SLogan Gunthorpe break; 65952eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_IMG1: 66052eabba5SLogan Gunthorpe active_addr = ioread32(&fi->active_img); 6616a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->img1); 662fcccd282SLogan Gunthorpe if (ioread16(&si->img_running) == SWITCHTEC_GEN3_IMG1_RUNNING) 6636a3d1b54SLogan Gunthorpe info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 66452eabba5SLogan Gunthorpe break; 66552eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_NVLOG: 6666a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->nvlog); 66752eabba5SLogan Gunthorpe break; 66852eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR0: 6696a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->vendor[0]); 67052eabba5SLogan Gunthorpe break; 67152eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR1: 6726a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->vendor[1]); 67352eabba5SLogan Gunthorpe break; 67452eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR2: 6756a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->vendor[2]); 67652eabba5SLogan Gunthorpe break; 67752eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR3: 6786a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->vendor[3]); 67952eabba5SLogan Gunthorpe break; 68052eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR4: 6816a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->vendor[4]); 68252eabba5SLogan Gunthorpe break; 68352eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR5: 6846a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->vendor[5]); 68552eabba5SLogan Gunthorpe break; 68652eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR6: 6876a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->vendor[6]); 68852eabba5SLogan Gunthorpe break; 68952eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR7: 6906a3d1b54SLogan Gunthorpe set_fw_info_part(info, &fi->vendor[7]); 69152eabba5SLogan Gunthorpe break; 69252eabba5SLogan Gunthorpe default: 69352eabba5SLogan Gunthorpe return -EINVAL; 69452eabba5SLogan Gunthorpe } 69552eabba5SLogan Gunthorpe 6966a3d1b54SLogan Gunthorpe if (info->address == active_addr) 6976a3d1b54SLogan Gunthorpe info->active |= SWITCHTEC_IOCTL_PART_ACTIVE; 6986a3d1b54SLogan Gunthorpe 6996a3d1b54SLogan Gunthorpe return 0; 7006a3d1b54SLogan Gunthorpe } 7016a3d1b54SLogan Gunthorpe 7024efa1d2eSKelvin Cao static int flash_part_info_gen4(struct switchtec_dev *stdev, 7034efa1d2eSKelvin Cao struct switchtec_ioctl_flash_part_info *info) 7044efa1d2eSKelvin Cao { 7054efa1d2eSKelvin Cao struct flash_info_regs_gen4 __iomem *fi = &stdev->mmio_flash_info->gen4; 7064efa1d2eSKelvin Cao struct sys_info_regs_gen4 __iomem *si = &stdev->mmio_sys_info->gen4; 7074efa1d2eSKelvin Cao struct active_partition_info_gen4 __iomem *af = &fi->active_flag; 7084efa1d2eSKelvin Cao 7094efa1d2eSKelvin Cao switch (info->flash_partition) { 7104efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_MAP_0: 7114efa1d2eSKelvin Cao set_fw_info_part(info, &fi->map0); 7124efa1d2eSKelvin Cao break; 7134efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_MAP_1: 7144efa1d2eSKelvin Cao set_fw_info_part(info, &fi->map1); 7154efa1d2eSKelvin Cao break; 7164efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_KEY_0: 7174efa1d2eSKelvin Cao set_fw_info_part(info, &fi->key0); 7184efa1d2eSKelvin Cao if (ioread8(&af->key) == SWITCHTEC_GEN4_KEY0_ACTIVE) 7194efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_ACTIVE; 7204efa1d2eSKelvin Cao if (ioread16(&si->key_running) == SWITCHTEC_GEN4_KEY0_RUNNING) 7214efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 7224efa1d2eSKelvin Cao break; 7234efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_KEY_1: 7244efa1d2eSKelvin Cao set_fw_info_part(info, &fi->key1); 7254efa1d2eSKelvin Cao if (ioread8(&af->key) == SWITCHTEC_GEN4_KEY1_ACTIVE) 7264efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_ACTIVE; 7274efa1d2eSKelvin Cao if (ioread16(&si->key_running) == SWITCHTEC_GEN4_KEY1_RUNNING) 7284efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 7294efa1d2eSKelvin Cao break; 7304efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_BL2_0: 7314efa1d2eSKelvin Cao set_fw_info_part(info, &fi->bl2_0); 7324efa1d2eSKelvin Cao if (ioread8(&af->bl2) == SWITCHTEC_GEN4_BL2_0_ACTIVE) 7334efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_ACTIVE; 7344efa1d2eSKelvin Cao if (ioread16(&si->bl2_running) == SWITCHTEC_GEN4_BL2_0_RUNNING) 7354efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 7364efa1d2eSKelvin Cao break; 7374efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_BL2_1: 7384efa1d2eSKelvin Cao set_fw_info_part(info, &fi->bl2_1); 7394efa1d2eSKelvin Cao if (ioread8(&af->bl2) == SWITCHTEC_GEN4_BL2_1_ACTIVE) 7404efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_ACTIVE; 7414efa1d2eSKelvin Cao if (ioread16(&si->bl2_running) == SWITCHTEC_GEN4_BL2_1_RUNNING) 7424efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 7434efa1d2eSKelvin Cao break; 7444efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_CFG0: 7454efa1d2eSKelvin Cao set_fw_info_part(info, &fi->cfg0); 7464efa1d2eSKelvin Cao if (ioread8(&af->cfg) == SWITCHTEC_GEN4_CFG0_ACTIVE) 7474efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_ACTIVE; 7484efa1d2eSKelvin Cao if (ioread16(&si->cfg_running) == SWITCHTEC_GEN4_CFG0_RUNNING) 7494efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 7504efa1d2eSKelvin Cao break; 7514efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_CFG1: 7524efa1d2eSKelvin Cao set_fw_info_part(info, &fi->cfg1); 7534efa1d2eSKelvin Cao if (ioread8(&af->cfg) == SWITCHTEC_GEN4_CFG1_ACTIVE) 7544efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_ACTIVE; 7554efa1d2eSKelvin Cao if (ioread16(&si->cfg_running) == SWITCHTEC_GEN4_CFG1_RUNNING) 7564efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 7574efa1d2eSKelvin Cao break; 7584efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_IMG0: 7594efa1d2eSKelvin Cao set_fw_info_part(info, &fi->img0); 7604efa1d2eSKelvin Cao if (ioread8(&af->img) == SWITCHTEC_GEN4_IMG0_ACTIVE) 7614efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_ACTIVE; 7624efa1d2eSKelvin Cao if (ioread16(&si->img_running) == SWITCHTEC_GEN4_IMG0_RUNNING) 7634efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 7644efa1d2eSKelvin Cao break; 7654efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_IMG1: 7664efa1d2eSKelvin Cao set_fw_info_part(info, &fi->img1); 7674efa1d2eSKelvin Cao if (ioread8(&af->img) == SWITCHTEC_GEN4_IMG1_ACTIVE) 7684efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_ACTIVE; 7694efa1d2eSKelvin Cao if (ioread16(&si->img_running) == SWITCHTEC_GEN4_IMG1_RUNNING) 7704efa1d2eSKelvin Cao info->active |= SWITCHTEC_IOCTL_PART_RUNNING; 7714efa1d2eSKelvin Cao break; 7724efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_NVLOG: 7734efa1d2eSKelvin Cao set_fw_info_part(info, &fi->nvlog); 7744efa1d2eSKelvin Cao break; 7754efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_VENDOR0: 7764efa1d2eSKelvin Cao set_fw_info_part(info, &fi->vendor[0]); 7774efa1d2eSKelvin Cao break; 7784efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_VENDOR1: 7794efa1d2eSKelvin Cao set_fw_info_part(info, &fi->vendor[1]); 7804efa1d2eSKelvin Cao break; 7814efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_VENDOR2: 7824efa1d2eSKelvin Cao set_fw_info_part(info, &fi->vendor[2]); 7834efa1d2eSKelvin Cao break; 7844efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_VENDOR3: 7854efa1d2eSKelvin Cao set_fw_info_part(info, &fi->vendor[3]); 7864efa1d2eSKelvin Cao break; 7874efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_VENDOR4: 7884efa1d2eSKelvin Cao set_fw_info_part(info, &fi->vendor[4]); 7894efa1d2eSKelvin Cao break; 7904efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_VENDOR5: 7914efa1d2eSKelvin Cao set_fw_info_part(info, &fi->vendor[5]); 7924efa1d2eSKelvin Cao break; 7934efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_VENDOR6: 7944efa1d2eSKelvin Cao set_fw_info_part(info, &fi->vendor[6]); 7954efa1d2eSKelvin Cao break; 7964efa1d2eSKelvin Cao case SWITCHTEC_IOCTL_PART_VENDOR7: 7974efa1d2eSKelvin Cao set_fw_info_part(info, &fi->vendor[7]); 7984efa1d2eSKelvin Cao break; 7994efa1d2eSKelvin Cao default: 8004efa1d2eSKelvin Cao return -EINVAL; 8014efa1d2eSKelvin Cao } 8024efa1d2eSKelvin Cao 8034efa1d2eSKelvin Cao return 0; 8044efa1d2eSKelvin Cao } 8054efa1d2eSKelvin Cao 8066a3d1b54SLogan Gunthorpe static int ioctl_flash_part_info(struct switchtec_dev *stdev, 8076a3d1b54SLogan Gunthorpe struct switchtec_ioctl_flash_part_info __user *uinfo) 8086a3d1b54SLogan Gunthorpe { 8096a3d1b54SLogan Gunthorpe int ret; 8106a3d1b54SLogan Gunthorpe struct switchtec_ioctl_flash_part_info info = {0}; 8116a3d1b54SLogan Gunthorpe 8126a3d1b54SLogan Gunthorpe if (copy_from_user(&info, uinfo, sizeof(info))) 8136a3d1b54SLogan Gunthorpe return -EFAULT; 8146a3d1b54SLogan Gunthorpe 8156a3d1b54SLogan Gunthorpe if (stdev->gen == SWITCHTEC_GEN3) { 8166a3d1b54SLogan Gunthorpe ret = flash_part_info_gen3(stdev, &info); 8176a3d1b54SLogan Gunthorpe if (ret) 8186a3d1b54SLogan Gunthorpe return ret; 8194efa1d2eSKelvin Cao } else if (stdev->gen == SWITCHTEC_GEN4) { 8204efa1d2eSKelvin Cao ret = flash_part_info_gen4(stdev, &info); 8214efa1d2eSKelvin Cao if (ret) 8224efa1d2eSKelvin Cao return ret; 8236a3d1b54SLogan Gunthorpe } else { 8246a3d1b54SLogan Gunthorpe return -ENOTSUPP; 8256a3d1b54SLogan Gunthorpe } 82652eabba5SLogan Gunthorpe 82752eabba5SLogan Gunthorpe if (copy_to_user(uinfo, &info, sizeof(info))) 82852eabba5SLogan Gunthorpe return -EFAULT; 82952eabba5SLogan Gunthorpe 83052eabba5SLogan Gunthorpe return 0; 83152eabba5SLogan Gunthorpe } 83252eabba5SLogan Gunthorpe 83352eabba5SLogan Gunthorpe static int ioctl_event_summary(struct switchtec_dev *stdev, 83452eabba5SLogan Gunthorpe struct switchtec_user *stuser, 835ba8a3982SWesley Sheng struct switchtec_ioctl_event_summary __user *usum, 836ba8a3982SWesley Sheng size_t size) 83752eabba5SLogan Gunthorpe { 838ba8a3982SWesley Sheng struct switchtec_ioctl_event_summary *s; 83952eabba5SLogan Gunthorpe int i; 84052eabba5SLogan Gunthorpe u32 reg; 841ba8a3982SWesley Sheng int ret = 0; 84252eabba5SLogan Gunthorpe 843ba8a3982SWesley Sheng s = kzalloc(sizeof(*s), GFP_KERNEL); 844ba8a3982SWesley Sheng if (!s) 845ba8a3982SWesley Sheng return -ENOMEM; 846ba8a3982SWesley Sheng 847ba8a3982SWesley Sheng s->global = ioread32(&stdev->mmio_sw_event->global_summary); 8486acdf7e1SLogan Gunthorpe s->part_bitmap = ioread64(&stdev->mmio_sw_event->part_event_bitmap); 849ba8a3982SWesley Sheng s->local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary); 85052eabba5SLogan Gunthorpe 85152eabba5SLogan Gunthorpe for (i = 0; i < stdev->partition_count; i++) { 85252eabba5SLogan Gunthorpe reg = ioread32(&stdev->mmio_part_cfg_all[i].part_event_summary); 853ba8a3982SWesley Sheng s->part[i] = reg; 85452eabba5SLogan Gunthorpe } 85552eabba5SLogan Gunthorpe 8567501a02aSWesley Sheng for (i = 0; i < stdev->pff_csr_count; i++) { 85752eabba5SLogan Gunthorpe reg = ioread32(&stdev->mmio_pff_csr[i].pff_event_summary); 858ba8a3982SWesley Sheng s->pff[i] = reg; 85952eabba5SLogan Gunthorpe } 86052eabba5SLogan Gunthorpe 861ba8a3982SWesley Sheng if (copy_to_user(usum, s, size)) { 862ba8a3982SWesley Sheng ret = -EFAULT; 863ba8a3982SWesley Sheng goto error_case; 864ba8a3982SWesley Sheng } 86552eabba5SLogan Gunthorpe 86652eabba5SLogan Gunthorpe stuser->event_cnt = atomic_read(&stdev->event_cnt); 86752eabba5SLogan Gunthorpe 868ba8a3982SWesley Sheng error_case: 869ba8a3982SWesley Sheng kfree(s); 870ba8a3982SWesley Sheng return ret; 87152eabba5SLogan Gunthorpe } 87252eabba5SLogan Gunthorpe 87352eabba5SLogan Gunthorpe static u32 __iomem *global_ev_reg(struct switchtec_dev *stdev, 87452eabba5SLogan Gunthorpe size_t offset, int index) 87552eabba5SLogan Gunthorpe { 87652eabba5SLogan Gunthorpe return (void __iomem *)stdev->mmio_sw_event + offset; 87752eabba5SLogan Gunthorpe } 87852eabba5SLogan Gunthorpe 87952eabba5SLogan Gunthorpe static u32 __iomem *part_ev_reg(struct switchtec_dev *stdev, 88052eabba5SLogan Gunthorpe size_t offset, int index) 88152eabba5SLogan Gunthorpe { 88252eabba5SLogan Gunthorpe return (void __iomem *)&stdev->mmio_part_cfg_all[index] + offset; 88352eabba5SLogan Gunthorpe } 88452eabba5SLogan Gunthorpe 88552eabba5SLogan Gunthorpe static u32 __iomem *pff_ev_reg(struct switchtec_dev *stdev, 88652eabba5SLogan Gunthorpe size_t offset, int index) 88752eabba5SLogan Gunthorpe { 88852eabba5SLogan Gunthorpe return (void __iomem *)&stdev->mmio_pff_csr[index] + offset; 88952eabba5SLogan Gunthorpe } 89052eabba5SLogan Gunthorpe 89152eabba5SLogan Gunthorpe #define EV_GLB(i, r)[i] = {offsetof(struct sw_event_regs, r), global_ev_reg} 89252eabba5SLogan Gunthorpe #define EV_PAR(i, r)[i] = {offsetof(struct part_cfg_regs, r), part_ev_reg} 89352eabba5SLogan Gunthorpe #define EV_PFF(i, r)[i] = {offsetof(struct pff_csr_regs, r), pff_ev_reg} 89452eabba5SLogan Gunthorpe 895f05f7355SColin Ian King static const struct event_reg { 89652eabba5SLogan Gunthorpe size_t offset; 89752eabba5SLogan Gunthorpe u32 __iomem *(*map_reg)(struct switchtec_dev *stdev, 89852eabba5SLogan Gunthorpe size_t offset, int index); 89952eabba5SLogan Gunthorpe } event_regs[] = { 90052eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_STACK_ERROR, stack_error_event_hdr), 90152eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_PPU_ERROR, ppu_error_event_hdr), 90252eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_ISP_ERROR, isp_error_event_hdr), 90352eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_SYS_RESET, sys_reset_event_hdr), 90452eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_EXC, fw_exception_hdr), 90552eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_NMI, fw_nmi_hdr), 90652eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_NON_FATAL, fw_non_fatal_hdr), 90752eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_FATAL, fw_fatal_hdr), 90852eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_TWI_MRPC_COMP, twi_mrpc_comp_hdr), 90952eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_TWI_MRPC_COMP_ASYNC, 91052eabba5SLogan Gunthorpe twi_mrpc_comp_async_hdr), 91152eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_CLI_MRPC_COMP, cli_mrpc_comp_hdr), 91252eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_CLI_MRPC_COMP_ASYNC, 91352eabba5SLogan Gunthorpe cli_mrpc_comp_async_hdr), 91452eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_GPIO_INT, gpio_interrupt_hdr), 915f0edce7aSLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_GFMS, gfms_event_hdr), 91652eabba5SLogan Gunthorpe EV_PAR(SWITCHTEC_IOCTL_EVENT_PART_RESET, part_reset_hdr), 91752eabba5SLogan Gunthorpe EV_PAR(SWITCHTEC_IOCTL_EVENT_MRPC_COMP, mrpc_comp_hdr), 91852eabba5SLogan Gunthorpe EV_PAR(SWITCHTEC_IOCTL_EVENT_MRPC_COMP_ASYNC, mrpc_comp_async_hdr), 91952eabba5SLogan Gunthorpe EV_PAR(SWITCHTEC_IOCTL_EVENT_DYN_PART_BIND_COMP, dyn_binding_hdr), 920a6b0ef9aSLogan Gunthorpe EV_PAR(SWITCHTEC_IOCTL_EVENT_INTERCOMM_REQ_NOTIFY, 921a6b0ef9aSLogan Gunthorpe intercomm_notify_hdr), 92252eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_AER_IN_P2P, aer_in_p2p_hdr), 92352eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_AER_IN_VEP, aer_in_vep_hdr), 92452eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_DPC, dpc_hdr), 92552eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_CTS, cts_hdr), 926a6b0ef9aSLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_UEC, uec_hdr), 92752eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_HOTPLUG, hotplug_hdr), 92852eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_IER, ier_hdr), 92952eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_THRESH, threshold_hdr), 93052eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_POWER_MGMT, power_mgmt_hdr), 93152eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_TLP_THROTTLING, tlp_throttling_hdr), 93252eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_FORCE_SPEED, force_speed_hdr), 93352eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_CREDIT_TIMEOUT, credit_timeout_hdr), 93452eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_LINK_STATE, link_state_hdr), 93552eabba5SLogan Gunthorpe }; 93652eabba5SLogan Gunthorpe 93752eabba5SLogan Gunthorpe static u32 __iomem *event_hdr_addr(struct switchtec_dev *stdev, 93852eabba5SLogan Gunthorpe int event_id, int index) 93952eabba5SLogan Gunthorpe { 94052eabba5SLogan Gunthorpe size_t off; 94152eabba5SLogan Gunthorpe 94252eabba5SLogan Gunthorpe if (event_id < 0 || event_id >= SWITCHTEC_IOCTL_MAX_EVENTS) 94352eabba5SLogan Gunthorpe return ERR_PTR(-EINVAL); 94452eabba5SLogan Gunthorpe 94552eabba5SLogan Gunthorpe off = event_regs[event_id].offset; 94652eabba5SLogan Gunthorpe 94752eabba5SLogan Gunthorpe if (event_regs[event_id].map_reg == part_ev_reg) { 94852eabba5SLogan Gunthorpe if (index == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX) 94952eabba5SLogan Gunthorpe index = stdev->partition; 95052eabba5SLogan Gunthorpe else if (index < 0 || index >= stdev->partition_count) 95152eabba5SLogan Gunthorpe return ERR_PTR(-EINVAL); 95252eabba5SLogan Gunthorpe } else if (event_regs[event_id].map_reg == pff_ev_reg) { 95352eabba5SLogan Gunthorpe if (index < 0 || index >= stdev->pff_csr_count) 95452eabba5SLogan Gunthorpe return ERR_PTR(-EINVAL); 95552eabba5SLogan Gunthorpe } 95652eabba5SLogan Gunthorpe 95752eabba5SLogan Gunthorpe return event_regs[event_id].map_reg(stdev, off, index); 95852eabba5SLogan Gunthorpe } 95952eabba5SLogan Gunthorpe 96052eabba5SLogan Gunthorpe static int event_ctl(struct switchtec_dev *stdev, 96152eabba5SLogan Gunthorpe struct switchtec_ioctl_event_ctl *ctl) 96252eabba5SLogan Gunthorpe { 96352eabba5SLogan Gunthorpe int i; 96452eabba5SLogan Gunthorpe u32 __iomem *reg; 96552eabba5SLogan Gunthorpe u32 hdr; 96652eabba5SLogan Gunthorpe 96752eabba5SLogan Gunthorpe reg = event_hdr_addr(stdev, ctl->event_id, ctl->index); 96852eabba5SLogan Gunthorpe if (IS_ERR(reg)) 96952eabba5SLogan Gunthorpe return PTR_ERR(reg); 97052eabba5SLogan Gunthorpe 97152eabba5SLogan Gunthorpe hdr = ioread32(reg); 97252eabba5SLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(ctl->data); i++) 97352eabba5SLogan Gunthorpe ctl->data[i] = ioread32(®[i + 1]); 97452eabba5SLogan Gunthorpe 97552eabba5SLogan Gunthorpe ctl->occurred = hdr & SWITCHTEC_EVENT_OCCURRED; 97652eabba5SLogan Gunthorpe ctl->count = (hdr >> 5) & 0xFF; 97752eabba5SLogan Gunthorpe 97852eabba5SLogan Gunthorpe if (!(ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_CLEAR)) 97952eabba5SLogan Gunthorpe hdr &= ~SWITCHTEC_EVENT_CLEAR; 98052eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL) 98152eabba5SLogan Gunthorpe hdr |= SWITCHTEC_EVENT_EN_IRQ; 98252eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_POLL) 98352eabba5SLogan Gunthorpe hdr &= ~SWITCHTEC_EVENT_EN_IRQ; 98452eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_LOG) 98552eabba5SLogan Gunthorpe hdr |= SWITCHTEC_EVENT_EN_LOG; 98652eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_LOG) 98752eabba5SLogan Gunthorpe hdr &= ~SWITCHTEC_EVENT_EN_LOG; 98852eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_CLI) 98952eabba5SLogan Gunthorpe hdr |= SWITCHTEC_EVENT_EN_CLI; 99052eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_CLI) 99152eabba5SLogan Gunthorpe hdr &= ~SWITCHTEC_EVENT_EN_CLI; 99252eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_FATAL) 99352eabba5SLogan Gunthorpe hdr |= SWITCHTEC_EVENT_FATAL; 99452eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_FATAL) 99552eabba5SLogan Gunthorpe hdr &= ~SWITCHTEC_EVENT_FATAL; 99652eabba5SLogan Gunthorpe 99752eabba5SLogan Gunthorpe if (ctl->flags) 99852eabba5SLogan Gunthorpe iowrite32(hdr, reg); 99952eabba5SLogan Gunthorpe 100052eabba5SLogan Gunthorpe ctl->flags = 0; 100152eabba5SLogan Gunthorpe if (hdr & SWITCHTEC_EVENT_EN_IRQ) 100252eabba5SLogan Gunthorpe ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL; 100352eabba5SLogan Gunthorpe if (hdr & SWITCHTEC_EVENT_EN_LOG) 100452eabba5SLogan Gunthorpe ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_LOG; 100552eabba5SLogan Gunthorpe if (hdr & SWITCHTEC_EVENT_EN_CLI) 100652eabba5SLogan Gunthorpe ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_CLI; 100752eabba5SLogan Gunthorpe if (hdr & SWITCHTEC_EVENT_FATAL) 100852eabba5SLogan Gunthorpe ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_FATAL; 100952eabba5SLogan Gunthorpe 101052eabba5SLogan Gunthorpe return 0; 101152eabba5SLogan Gunthorpe } 101252eabba5SLogan Gunthorpe 101352eabba5SLogan Gunthorpe static int ioctl_event_ctl(struct switchtec_dev *stdev, 101452eabba5SLogan Gunthorpe struct switchtec_ioctl_event_ctl __user *uctl) 101552eabba5SLogan Gunthorpe { 101652eabba5SLogan Gunthorpe int ret; 101752eabba5SLogan Gunthorpe int nr_idxs; 1018e4a7dca5SJoey Zhang unsigned int event_flags; 101952eabba5SLogan Gunthorpe struct switchtec_ioctl_event_ctl ctl; 102052eabba5SLogan Gunthorpe 102152eabba5SLogan Gunthorpe if (copy_from_user(&ctl, uctl, sizeof(ctl))) 102252eabba5SLogan Gunthorpe return -EFAULT; 102352eabba5SLogan Gunthorpe 102452eabba5SLogan Gunthorpe if (ctl.event_id >= SWITCHTEC_IOCTL_MAX_EVENTS) 102552eabba5SLogan Gunthorpe return -EINVAL; 102652eabba5SLogan Gunthorpe 102752eabba5SLogan Gunthorpe if (ctl.flags & SWITCHTEC_IOCTL_EVENT_FLAG_UNUSED) 102852eabba5SLogan Gunthorpe return -EINVAL; 102952eabba5SLogan Gunthorpe 103052eabba5SLogan Gunthorpe if (ctl.index == SWITCHTEC_IOCTL_EVENT_IDX_ALL) { 103152eabba5SLogan Gunthorpe if (event_regs[ctl.event_id].map_reg == global_ev_reg) 103252eabba5SLogan Gunthorpe nr_idxs = 1; 103352eabba5SLogan Gunthorpe else if (event_regs[ctl.event_id].map_reg == part_ev_reg) 103452eabba5SLogan Gunthorpe nr_idxs = stdev->partition_count; 103552eabba5SLogan Gunthorpe else if (event_regs[ctl.event_id].map_reg == pff_ev_reg) 103652eabba5SLogan Gunthorpe nr_idxs = stdev->pff_csr_count; 103752eabba5SLogan Gunthorpe else 103852eabba5SLogan Gunthorpe return -EINVAL; 103952eabba5SLogan Gunthorpe 1040e4a7dca5SJoey Zhang event_flags = ctl.flags; 104152eabba5SLogan Gunthorpe for (ctl.index = 0; ctl.index < nr_idxs; ctl.index++) { 1042e4a7dca5SJoey Zhang ctl.flags = event_flags; 104352eabba5SLogan Gunthorpe ret = event_ctl(stdev, &ctl); 104452eabba5SLogan Gunthorpe if (ret < 0) 104552eabba5SLogan Gunthorpe return ret; 104652eabba5SLogan Gunthorpe } 104752eabba5SLogan Gunthorpe } else { 104852eabba5SLogan Gunthorpe ret = event_ctl(stdev, &ctl); 104952eabba5SLogan Gunthorpe if (ret < 0) 105052eabba5SLogan Gunthorpe return ret; 105152eabba5SLogan Gunthorpe } 105252eabba5SLogan Gunthorpe 105352eabba5SLogan Gunthorpe if (copy_to_user(uctl, &ctl, sizeof(ctl))) 105452eabba5SLogan Gunthorpe return -EFAULT; 105552eabba5SLogan Gunthorpe 105652eabba5SLogan Gunthorpe return 0; 105752eabba5SLogan Gunthorpe } 105852eabba5SLogan Gunthorpe 105952eabba5SLogan Gunthorpe static int ioctl_pff_to_port(struct switchtec_dev *stdev, 106052eabba5SLogan Gunthorpe struct switchtec_ioctl_pff_port *up) 106152eabba5SLogan Gunthorpe { 106252eabba5SLogan Gunthorpe int i, part; 106352eabba5SLogan Gunthorpe u32 reg; 106452eabba5SLogan Gunthorpe struct part_cfg_regs *pcfg; 106552eabba5SLogan Gunthorpe struct switchtec_ioctl_pff_port p; 106652eabba5SLogan Gunthorpe 106752eabba5SLogan Gunthorpe if (copy_from_user(&p, up, sizeof(p))) 106852eabba5SLogan Gunthorpe return -EFAULT; 106952eabba5SLogan Gunthorpe 107052eabba5SLogan Gunthorpe p.port = -1; 107152eabba5SLogan Gunthorpe for (part = 0; part < stdev->partition_count; part++) { 107252eabba5SLogan Gunthorpe pcfg = &stdev->mmio_part_cfg_all[part]; 107352eabba5SLogan Gunthorpe p.partition = part; 107452eabba5SLogan Gunthorpe 107552eabba5SLogan Gunthorpe reg = ioread32(&pcfg->usp_pff_inst_id); 107652eabba5SLogan Gunthorpe if (reg == p.pff) { 107752eabba5SLogan Gunthorpe p.port = 0; 107852eabba5SLogan Gunthorpe break; 107952eabba5SLogan Gunthorpe } 108052eabba5SLogan Gunthorpe 108152eabba5SLogan Gunthorpe reg = ioread32(&pcfg->vep_pff_inst_id); 108252eabba5SLogan Gunthorpe if (reg == p.pff) { 108352eabba5SLogan Gunthorpe p.port = SWITCHTEC_IOCTL_PFF_VEP; 108452eabba5SLogan Gunthorpe break; 108552eabba5SLogan Gunthorpe } 108652eabba5SLogan Gunthorpe 108752eabba5SLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(pcfg->dsp_pff_inst_id); i++) { 108852eabba5SLogan Gunthorpe reg = ioread32(&pcfg->dsp_pff_inst_id[i]); 108952eabba5SLogan Gunthorpe if (reg != p.pff) 109052eabba5SLogan Gunthorpe continue; 109152eabba5SLogan Gunthorpe 109252eabba5SLogan Gunthorpe p.port = i + 1; 109352eabba5SLogan Gunthorpe break; 109452eabba5SLogan Gunthorpe } 109552eabba5SLogan Gunthorpe 109652eabba5SLogan Gunthorpe if (p.port != -1) 109752eabba5SLogan Gunthorpe break; 109852eabba5SLogan Gunthorpe } 109952eabba5SLogan Gunthorpe 110052eabba5SLogan Gunthorpe if (copy_to_user(up, &p, sizeof(p))) 110152eabba5SLogan Gunthorpe return -EFAULT; 110252eabba5SLogan Gunthorpe 110352eabba5SLogan Gunthorpe return 0; 110452eabba5SLogan Gunthorpe } 110552eabba5SLogan Gunthorpe 110652eabba5SLogan Gunthorpe static int ioctl_port_to_pff(struct switchtec_dev *stdev, 110752eabba5SLogan Gunthorpe struct switchtec_ioctl_pff_port *up) 110852eabba5SLogan Gunthorpe { 110952eabba5SLogan Gunthorpe struct switchtec_ioctl_pff_port p; 111052eabba5SLogan Gunthorpe struct part_cfg_regs *pcfg; 111152eabba5SLogan Gunthorpe 111252eabba5SLogan Gunthorpe if (copy_from_user(&p, up, sizeof(p))) 111352eabba5SLogan Gunthorpe return -EFAULT; 111452eabba5SLogan Gunthorpe 111552eabba5SLogan Gunthorpe if (p.partition == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX) 111652eabba5SLogan Gunthorpe pcfg = stdev->mmio_part_cfg; 111752eabba5SLogan Gunthorpe else if (p.partition < stdev->partition_count) 111852eabba5SLogan Gunthorpe pcfg = &stdev->mmio_part_cfg_all[p.partition]; 111952eabba5SLogan Gunthorpe else 112052eabba5SLogan Gunthorpe return -EINVAL; 112152eabba5SLogan Gunthorpe 112252eabba5SLogan Gunthorpe switch (p.port) { 112352eabba5SLogan Gunthorpe case 0: 112452eabba5SLogan Gunthorpe p.pff = ioread32(&pcfg->usp_pff_inst_id); 112552eabba5SLogan Gunthorpe break; 112652eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PFF_VEP: 112752eabba5SLogan Gunthorpe p.pff = ioread32(&pcfg->vep_pff_inst_id); 112852eabba5SLogan Gunthorpe break; 112952eabba5SLogan Gunthorpe default: 113052eabba5SLogan Gunthorpe if (p.port > ARRAY_SIZE(pcfg->dsp_pff_inst_id)) 113152eabba5SLogan Gunthorpe return -EINVAL; 113246feb6b4SGustavo A. R. Silva p.port = array_index_nospec(p.port, 113346feb6b4SGustavo A. R. Silva ARRAY_SIZE(pcfg->dsp_pff_inst_id) + 1); 113452eabba5SLogan Gunthorpe p.pff = ioread32(&pcfg->dsp_pff_inst_id[p.port - 1]); 113552eabba5SLogan Gunthorpe break; 113652eabba5SLogan Gunthorpe } 113752eabba5SLogan Gunthorpe 113852eabba5SLogan Gunthorpe if (copy_to_user(up, &p, sizeof(p))) 113952eabba5SLogan Gunthorpe return -EFAULT; 114052eabba5SLogan Gunthorpe 114152eabba5SLogan Gunthorpe return 0; 114252eabba5SLogan Gunthorpe } 114352eabba5SLogan Gunthorpe 114452eabba5SLogan Gunthorpe static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd, 114552eabba5SLogan Gunthorpe unsigned long arg) 114652eabba5SLogan Gunthorpe { 114752eabba5SLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 114852eabba5SLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 114952eabba5SLogan Gunthorpe int rc; 115052eabba5SLogan Gunthorpe void __user *argp = (void __user *)arg; 115152eabba5SLogan Gunthorpe 115252eabba5SLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 115352eabba5SLogan Gunthorpe if (rc) 115452eabba5SLogan Gunthorpe return rc; 115552eabba5SLogan Gunthorpe 115652eabba5SLogan Gunthorpe switch (cmd) { 115752eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_FLASH_INFO: 115852eabba5SLogan Gunthorpe rc = ioctl_flash_info(stdev, argp); 115952eabba5SLogan Gunthorpe break; 116052eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_FLASH_PART_INFO: 116152eabba5SLogan Gunthorpe rc = ioctl_flash_part_info(stdev, argp); 116252eabba5SLogan Gunthorpe break; 1163ba8a3982SWesley Sheng case SWITCHTEC_IOCTL_EVENT_SUMMARY_LEGACY: 1164ba8a3982SWesley Sheng rc = ioctl_event_summary(stdev, stuser, argp, 1165ba8a3982SWesley Sheng sizeof(struct switchtec_ioctl_event_summary_legacy)); 116652eabba5SLogan Gunthorpe break; 116752eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_EVENT_CTL: 116852eabba5SLogan Gunthorpe rc = ioctl_event_ctl(stdev, argp); 116952eabba5SLogan Gunthorpe break; 117052eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PFF_TO_PORT: 117152eabba5SLogan Gunthorpe rc = ioctl_pff_to_port(stdev, argp); 117252eabba5SLogan Gunthorpe break; 117352eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PORT_TO_PFF: 117452eabba5SLogan Gunthorpe rc = ioctl_port_to_pff(stdev, argp); 117552eabba5SLogan Gunthorpe break; 1176ba8a3982SWesley Sheng case SWITCHTEC_IOCTL_EVENT_SUMMARY: 1177ba8a3982SWesley Sheng rc = ioctl_event_summary(stdev, stuser, argp, 1178ba8a3982SWesley Sheng sizeof(struct switchtec_ioctl_event_summary)); 1179ba8a3982SWesley Sheng break; 118052eabba5SLogan Gunthorpe default: 118152eabba5SLogan Gunthorpe rc = -ENOTTY; 118252eabba5SLogan Gunthorpe break; 118352eabba5SLogan Gunthorpe } 118452eabba5SLogan Gunthorpe 118552eabba5SLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 118652eabba5SLogan Gunthorpe return rc; 118752eabba5SLogan Gunthorpe } 118852eabba5SLogan Gunthorpe 1189080b47deSLogan Gunthorpe static const struct file_operations switchtec_fops = { 1190080b47deSLogan Gunthorpe .owner = THIS_MODULE, 1191080b47deSLogan Gunthorpe .open = switchtec_dev_open, 1192080b47deSLogan Gunthorpe .release = switchtec_dev_release, 1193080b47deSLogan Gunthorpe .write = switchtec_dev_write, 1194080b47deSLogan Gunthorpe .read = switchtec_dev_read, 1195080b47deSLogan Gunthorpe .poll = switchtec_dev_poll, 119652eabba5SLogan Gunthorpe .unlocked_ioctl = switchtec_dev_ioctl, 11971832f2d8SArnd Bergmann .compat_ioctl = compat_ptr_ioctl, 1198080b47deSLogan Gunthorpe }; 1199080b47deSLogan Gunthorpe 120048c302dcSLogan Gunthorpe static void link_event_work(struct work_struct *work) 120148c302dcSLogan Gunthorpe { 120248c302dcSLogan Gunthorpe struct switchtec_dev *stdev; 120348c302dcSLogan Gunthorpe 120448c302dcSLogan Gunthorpe stdev = container_of(work, struct switchtec_dev, link_event_work); 120548c302dcSLogan Gunthorpe 120648c302dcSLogan Gunthorpe if (stdev->link_notifier) 120748c302dcSLogan Gunthorpe stdev->link_notifier(stdev); 120848c302dcSLogan Gunthorpe } 120948c302dcSLogan Gunthorpe 121048c302dcSLogan Gunthorpe static void check_link_state_events(struct switchtec_dev *stdev) 121148c302dcSLogan Gunthorpe { 121248c302dcSLogan Gunthorpe int idx; 121348c302dcSLogan Gunthorpe u32 reg; 121448c302dcSLogan Gunthorpe int count; 121548c302dcSLogan Gunthorpe int occurred = 0; 121648c302dcSLogan Gunthorpe 121748c302dcSLogan Gunthorpe for (idx = 0; idx < stdev->pff_csr_count; idx++) { 121848c302dcSLogan Gunthorpe reg = ioread32(&stdev->mmio_pff_csr[idx].link_state_hdr); 121948c302dcSLogan Gunthorpe dev_dbg(&stdev->dev, "link_state: %d->%08x\n", idx, reg); 122048c302dcSLogan Gunthorpe count = (reg >> 5) & 0xFF; 122148c302dcSLogan Gunthorpe 122248c302dcSLogan Gunthorpe if (count != stdev->link_event_count[idx]) { 122348c302dcSLogan Gunthorpe occurred = 1; 122448c302dcSLogan Gunthorpe stdev->link_event_count[idx] = count; 122548c302dcSLogan Gunthorpe } 122648c302dcSLogan Gunthorpe } 122748c302dcSLogan Gunthorpe 122848c302dcSLogan Gunthorpe if (occurred) 122948c302dcSLogan Gunthorpe schedule_work(&stdev->link_event_work); 123048c302dcSLogan Gunthorpe } 123148c302dcSLogan Gunthorpe 123248c302dcSLogan Gunthorpe static void enable_link_state_events(struct switchtec_dev *stdev) 123348c302dcSLogan Gunthorpe { 123448c302dcSLogan Gunthorpe int idx; 123548c302dcSLogan Gunthorpe 123648c302dcSLogan Gunthorpe for (idx = 0; idx < stdev->pff_csr_count; idx++) { 123748c302dcSLogan Gunthorpe iowrite32(SWITCHTEC_EVENT_CLEAR | 123848c302dcSLogan Gunthorpe SWITCHTEC_EVENT_EN_IRQ, 123948c302dcSLogan Gunthorpe &stdev->mmio_pff_csr[idx].link_state_hdr); 124048c302dcSLogan Gunthorpe } 124148c302dcSLogan Gunthorpe } 124248c302dcSLogan Gunthorpe 1243f7eb7b8aSWesley Sheng static void enable_dma_mrpc(struct switchtec_dev *stdev) 1244f7eb7b8aSWesley Sheng { 1245f7eb7b8aSWesley Sheng writeq(stdev->dma_mrpc_dma_addr, &stdev->mmio_mrpc->dma_addr); 1246f7eb7b8aSWesley Sheng flush_wc_buf(stdev); 1247f7eb7b8aSWesley Sheng iowrite32(SWITCHTEC_DMA_MRPC_EN, &stdev->mmio_mrpc->dma_en); 1248f7eb7b8aSWesley Sheng } 1249f7eb7b8aSWesley Sheng 1250080b47deSLogan Gunthorpe static void stdev_release(struct device *dev) 1251080b47deSLogan Gunthorpe { 1252080b47deSLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 1253080b47deSLogan Gunthorpe 1254f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) { 1255f7eb7b8aSWesley Sheng iowrite32(0, &stdev->mmio_mrpc->dma_en); 1256f7eb7b8aSWesley Sheng flush_wc_buf(stdev); 1257f7eb7b8aSWesley Sheng writeq(0, &stdev->mmio_mrpc->dma_addr); 1258f7eb7b8aSWesley Sheng dma_free_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc), 1259f7eb7b8aSWesley Sheng stdev->dma_mrpc, stdev->dma_mrpc_dma_addr); 1260f7eb7b8aSWesley Sheng } 1261080b47deSLogan Gunthorpe kfree(stdev); 1262080b47deSLogan Gunthorpe } 1263080b47deSLogan Gunthorpe 1264080b47deSLogan Gunthorpe static void stdev_kill(struct switchtec_dev *stdev) 1265080b47deSLogan Gunthorpe { 1266080b47deSLogan Gunthorpe struct switchtec_user *stuser, *tmpuser; 1267080b47deSLogan Gunthorpe 1268080b47deSLogan Gunthorpe pci_clear_master(stdev->pdev); 1269080b47deSLogan Gunthorpe 1270080b47deSLogan Gunthorpe cancel_delayed_work_sync(&stdev->mrpc_timeout); 1271080b47deSLogan Gunthorpe 1272080b47deSLogan Gunthorpe /* Mark the hardware as unavailable and complete all completions */ 1273080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 1274080b47deSLogan Gunthorpe stdev->alive = false; 1275080b47deSLogan Gunthorpe 1276080b47deSLogan Gunthorpe /* Wake up and kill any users waiting on an MRPC request */ 1277080b47deSLogan Gunthorpe list_for_each_entry_safe(stuser, tmpuser, &stdev->mrpc_queue, list) { 1278deaa0a8aSSebastian Andrzej Siewior stuser->cmd_done = true; 1279deaa0a8aSSebastian Andrzej Siewior wake_up_interruptible(&stuser->cmd_comp); 1280080b47deSLogan Gunthorpe list_del_init(&stuser->list); 1281080b47deSLogan Gunthorpe stuser_put(stuser); 1282080b47deSLogan Gunthorpe } 1283080b47deSLogan Gunthorpe 1284080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 1285080b47deSLogan Gunthorpe 1286080b47deSLogan Gunthorpe /* Wake up any users waiting on event_wq */ 1287080b47deSLogan Gunthorpe wake_up_interruptible(&stdev->event_wq); 1288080b47deSLogan Gunthorpe } 1289080b47deSLogan Gunthorpe 1290080b47deSLogan Gunthorpe static struct switchtec_dev *stdev_create(struct pci_dev *pdev) 1291080b47deSLogan Gunthorpe { 1292080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 1293080b47deSLogan Gunthorpe int minor; 1294080b47deSLogan Gunthorpe struct device *dev; 1295080b47deSLogan Gunthorpe struct cdev *cdev; 1296080b47deSLogan Gunthorpe int rc; 1297080b47deSLogan Gunthorpe 1298080b47deSLogan Gunthorpe stdev = kzalloc_node(sizeof(*stdev), GFP_KERNEL, 1299080b47deSLogan Gunthorpe dev_to_node(&pdev->dev)); 1300080b47deSLogan Gunthorpe if (!stdev) 1301080b47deSLogan Gunthorpe return ERR_PTR(-ENOMEM); 1302080b47deSLogan Gunthorpe 1303080b47deSLogan Gunthorpe stdev->alive = true; 1304080b47deSLogan Gunthorpe stdev->pdev = pdev; 1305080b47deSLogan Gunthorpe INIT_LIST_HEAD(&stdev->mrpc_queue); 1306080b47deSLogan Gunthorpe mutex_init(&stdev->mrpc_mutex); 1307080b47deSLogan Gunthorpe stdev->mrpc_busy = 0; 1308080b47deSLogan Gunthorpe INIT_WORK(&stdev->mrpc_work, mrpc_event_work); 1309080b47deSLogan Gunthorpe INIT_DELAYED_WORK(&stdev->mrpc_timeout, mrpc_timeout_work); 131048c302dcSLogan Gunthorpe INIT_WORK(&stdev->link_event_work, link_event_work); 1311080b47deSLogan Gunthorpe init_waitqueue_head(&stdev->event_wq); 1312080b47deSLogan Gunthorpe atomic_set(&stdev->event_cnt, 0); 1313080b47deSLogan Gunthorpe 1314080b47deSLogan Gunthorpe dev = &stdev->dev; 1315080b47deSLogan Gunthorpe device_initialize(dev); 1316080b47deSLogan Gunthorpe dev->class = switchtec_class; 1317080b47deSLogan Gunthorpe dev->parent = &pdev->dev; 13185d8e1881SLogan Gunthorpe dev->groups = switchtec_device_groups; 1319080b47deSLogan Gunthorpe dev->release = stdev_release; 1320080b47deSLogan Gunthorpe 1321080b47deSLogan Gunthorpe minor = ida_simple_get(&switchtec_minor_ida, 0, 0, 1322080b47deSLogan Gunthorpe GFP_KERNEL); 1323080b47deSLogan Gunthorpe if (minor < 0) { 1324080b47deSLogan Gunthorpe rc = minor; 1325080b47deSLogan Gunthorpe goto err_put; 1326080b47deSLogan Gunthorpe } 1327080b47deSLogan Gunthorpe 1328080b47deSLogan Gunthorpe dev->devt = MKDEV(MAJOR(switchtec_devt), minor); 1329080b47deSLogan Gunthorpe dev_set_name(dev, "switchtec%d", minor); 1330080b47deSLogan Gunthorpe 1331080b47deSLogan Gunthorpe cdev = &stdev->cdev; 1332080b47deSLogan Gunthorpe cdev_init(cdev, &switchtec_fops); 1333080b47deSLogan Gunthorpe cdev->owner = THIS_MODULE; 1334080b47deSLogan Gunthorpe 1335080b47deSLogan Gunthorpe return stdev; 1336080b47deSLogan Gunthorpe 1337080b47deSLogan Gunthorpe err_put: 1338080b47deSLogan Gunthorpe put_device(&stdev->dev); 1339080b47deSLogan Gunthorpe return ERR_PTR(rc); 1340080b47deSLogan Gunthorpe } 1341080b47deSLogan Gunthorpe 134252eabba5SLogan Gunthorpe static int mask_event(struct switchtec_dev *stdev, int eid, int idx) 134352eabba5SLogan Gunthorpe { 134452eabba5SLogan Gunthorpe size_t off = event_regs[eid].offset; 134552eabba5SLogan Gunthorpe u32 __iomem *hdr_reg; 134652eabba5SLogan Gunthorpe u32 hdr; 134752eabba5SLogan Gunthorpe 134852eabba5SLogan Gunthorpe hdr_reg = event_regs[eid].map_reg(stdev, off, idx); 134952eabba5SLogan Gunthorpe hdr = ioread32(hdr_reg); 135052eabba5SLogan Gunthorpe 135152eabba5SLogan Gunthorpe if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ)) 135252eabba5SLogan Gunthorpe return 0; 135352eabba5SLogan Gunthorpe 135452eabba5SLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %d %d %x\n", __func__, eid, idx, hdr); 135552eabba5SLogan Gunthorpe hdr &= ~(SWITCHTEC_EVENT_EN_IRQ | SWITCHTEC_EVENT_OCCURRED); 135652eabba5SLogan Gunthorpe iowrite32(hdr, hdr_reg); 135752eabba5SLogan Gunthorpe 135852eabba5SLogan Gunthorpe return 1; 135952eabba5SLogan Gunthorpe } 136052eabba5SLogan Gunthorpe 136152eabba5SLogan Gunthorpe static int mask_all_events(struct switchtec_dev *stdev, int eid) 136252eabba5SLogan Gunthorpe { 136352eabba5SLogan Gunthorpe int idx; 136452eabba5SLogan Gunthorpe int count = 0; 136552eabba5SLogan Gunthorpe 136652eabba5SLogan Gunthorpe if (event_regs[eid].map_reg == part_ev_reg) { 136752eabba5SLogan Gunthorpe for (idx = 0; idx < stdev->partition_count; idx++) 136852eabba5SLogan Gunthorpe count += mask_event(stdev, eid, idx); 136952eabba5SLogan Gunthorpe } else if (event_regs[eid].map_reg == pff_ev_reg) { 137052eabba5SLogan Gunthorpe for (idx = 0; idx < stdev->pff_csr_count; idx++) { 137152eabba5SLogan Gunthorpe if (!stdev->pff_local[idx]) 137252eabba5SLogan Gunthorpe continue; 137348c302dcSLogan Gunthorpe 137452eabba5SLogan Gunthorpe count += mask_event(stdev, eid, idx); 137552eabba5SLogan Gunthorpe } 137652eabba5SLogan Gunthorpe } else { 137752eabba5SLogan Gunthorpe count += mask_event(stdev, eid, 0); 137852eabba5SLogan Gunthorpe } 137952eabba5SLogan Gunthorpe 138052eabba5SLogan Gunthorpe return count; 138152eabba5SLogan Gunthorpe } 138252eabba5SLogan Gunthorpe 1383080b47deSLogan Gunthorpe static irqreturn_t switchtec_event_isr(int irq, void *dev) 1384080b47deSLogan Gunthorpe { 1385080b47deSLogan Gunthorpe struct switchtec_dev *stdev = dev; 1386080b47deSLogan Gunthorpe u32 reg; 1387080b47deSLogan Gunthorpe irqreturn_t ret = IRQ_NONE; 138852eabba5SLogan Gunthorpe int eid, event_count = 0; 1389080b47deSLogan Gunthorpe 1390080b47deSLogan Gunthorpe reg = ioread32(&stdev->mmio_part_cfg->mrpc_comp_hdr); 1391080b47deSLogan Gunthorpe if (reg & SWITCHTEC_EVENT_OCCURRED) { 1392080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: mrpc comp\n", __func__); 1393080b47deSLogan Gunthorpe ret = IRQ_HANDLED; 1394080b47deSLogan Gunthorpe schedule_work(&stdev->mrpc_work); 1395080b47deSLogan Gunthorpe iowrite32(reg, &stdev->mmio_part_cfg->mrpc_comp_hdr); 1396080b47deSLogan Gunthorpe } 1397080b47deSLogan Gunthorpe 139848c302dcSLogan Gunthorpe check_link_state_events(stdev); 139948c302dcSLogan Gunthorpe 14002085747dSWesley Sheng for (eid = 0; eid < SWITCHTEC_IOCTL_MAX_EVENTS; eid++) { 14012085747dSWesley Sheng if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE || 14022085747dSWesley Sheng eid == SWITCHTEC_IOCTL_EVENT_MRPC_COMP) 14032085747dSWesley Sheng continue; 14042085747dSWesley Sheng 140552eabba5SLogan Gunthorpe event_count += mask_all_events(stdev, eid); 14062085747dSWesley Sheng } 140752eabba5SLogan Gunthorpe 140852eabba5SLogan Gunthorpe if (event_count) { 140952eabba5SLogan Gunthorpe atomic_inc(&stdev->event_cnt); 141052eabba5SLogan Gunthorpe wake_up_interruptible(&stdev->event_wq); 141152eabba5SLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %d events\n", __func__, 141252eabba5SLogan Gunthorpe event_count); 141352eabba5SLogan Gunthorpe return IRQ_HANDLED; 141452eabba5SLogan Gunthorpe } 141552eabba5SLogan Gunthorpe 1416080b47deSLogan Gunthorpe return ret; 1417080b47deSLogan Gunthorpe } 1418080b47deSLogan Gunthorpe 1419f7eb7b8aSWesley Sheng 1420f7eb7b8aSWesley Sheng static irqreturn_t switchtec_dma_mrpc_isr(int irq, void *dev) 1421f7eb7b8aSWesley Sheng { 1422f7eb7b8aSWesley Sheng struct switchtec_dev *stdev = dev; 1423f7eb7b8aSWesley Sheng irqreturn_t ret = IRQ_NONE; 1424f7eb7b8aSWesley Sheng 1425f7eb7b8aSWesley Sheng iowrite32(SWITCHTEC_EVENT_CLEAR | 1426f7eb7b8aSWesley Sheng SWITCHTEC_EVENT_EN_IRQ, 1427f7eb7b8aSWesley Sheng &stdev->mmio_part_cfg->mrpc_comp_hdr); 1428f7eb7b8aSWesley Sheng schedule_work(&stdev->mrpc_work); 1429f7eb7b8aSWesley Sheng 1430f7eb7b8aSWesley Sheng ret = IRQ_HANDLED; 1431f7eb7b8aSWesley Sheng return ret; 1432f7eb7b8aSWesley Sheng } 1433f7eb7b8aSWesley Sheng 1434080b47deSLogan Gunthorpe static int switchtec_init_isr(struct switchtec_dev *stdev) 1435080b47deSLogan Gunthorpe { 1436080b47deSLogan Gunthorpe int nvecs; 1437080b47deSLogan Gunthorpe int event_irq; 1438f7eb7b8aSWesley Sheng int dma_mrpc_irq; 1439f7eb7b8aSWesley Sheng int rc; 1440080b47deSLogan Gunthorpe 1441fcdf8e95SLogan Gunthorpe if (nirqs < 4) 1442fcdf8e95SLogan Gunthorpe nirqs = 4; 1443fcdf8e95SLogan Gunthorpe 1444fcdf8e95SLogan Gunthorpe nvecs = pci_alloc_irq_vectors(stdev->pdev, 1, nirqs, 1445fcdf8e95SLogan Gunthorpe PCI_IRQ_MSIX | PCI_IRQ_MSI | 1446fcdf8e95SLogan Gunthorpe PCI_IRQ_VIRTUAL); 1447080b47deSLogan Gunthorpe if (nvecs < 0) 1448080b47deSLogan Gunthorpe return nvecs; 1449080b47deSLogan Gunthorpe 14509375646bSLogan Gunthorpe event_irq = ioread16(&stdev->mmio_part_cfg->vep_vector_number); 1451080b47deSLogan Gunthorpe if (event_irq < 0 || event_irq >= nvecs) 1452080b47deSLogan Gunthorpe return -EFAULT; 1453080b47deSLogan Gunthorpe 1454080b47deSLogan Gunthorpe event_irq = pci_irq_vector(stdev->pdev, event_irq); 1455080b47deSLogan Gunthorpe if (event_irq < 0) 1456080b47deSLogan Gunthorpe return event_irq; 1457080b47deSLogan Gunthorpe 1458f7eb7b8aSWesley Sheng rc = devm_request_irq(&stdev->pdev->dev, event_irq, 1459080b47deSLogan Gunthorpe switchtec_event_isr, 0, 1460080b47deSLogan Gunthorpe KBUILD_MODNAME, stdev); 1461f7eb7b8aSWesley Sheng 1462f7eb7b8aSWesley Sheng if (rc) 1463f7eb7b8aSWesley Sheng return rc; 1464f7eb7b8aSWesley Sheng 1465f7eb7b8aSWesley Sheng if (!stdev->dma_mrpc) 1466f7eb7b8aSWesley Sheng return rc; 1467f7eb7b8aSWesley Sheng 1468f7eb7b8aSWesley Sheng dma_mrpc_irq = ioread32(&stdev->mmio_mrpc->dma_vector); 1469f7eb7b8aSWesley Sheng if (dma_mrpc_irq < 0 || dma_mrpc_irq >= nvecs) 1470f7eb7b8aSWesley Sheng return -EFAULT; 1471f7eb7b8aSWesley Sheng 1472f7eb7b8aSWesley Sheng dma_mrpc_irq = pci_irq_vector(stdev->pdev, dma_mrpc_irq); 1473f7eb7b8aSWesley Sheng if (dma_mrpc_irq < 0) 1474f7eb7b8aSWesley Sheng return dma_mrpc_irq; 1475f7eb7b8aSWesley Sheng 1476f7eb7b8aSWesley Sheng rc = devm_request_irq(&stdev->pdev->dev, dma_mrpc_irq, 1477f7eb7b8aSWesley Sheng switchtec_dma_mrpc_isr, 0, 1478f7eb7b8aSWesley Sheng KBUILD_MODNAME, stdev); 1479f7eb7b8aSWesley Sheng 1480f7eb7b8aSWesley Sheng return rc; 1481080b47deSLogan Gunthorpe } 1482080b47deSLogan Gunthorpe 1483080b47deSLogan Gunthorpe static void init_pff(struct switchtec_dev *stdev) 1484080b47deSLogan Gunthorpe { 1485080b47deSLogan Gunthorpe int i; 1486080b47deSLogan Gunthorpe u32 reg; 1487080b47deSLogan Gunthorpe struct part_cfg_regs *pcfg = stdev->mmio_part_cfg; 1488080b47deSLogan Gunthorpe 1489080b47deSLogan Gunthorpe for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { 1490080b47deSLogan Gunthorpe reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id); 1491cfdfc14eSDoug Meyer if (reg != PCI_VENDOR_ID_MICROSEMI) 1492080b47deSLogan Gunthorpe break; 1493080b47deSLogan Gunthorpe } 1494080b47deSLogan Gunthorpe 1495080b47deSLogan Gunthorpe stdev->pff_csr_count = i; 1496080b47deSLogan Gunthorpe 1497080b47deSLogan Gunthorpe reg = ioread32(&pcfg->usp_pff_inst_id); 14987501a02aSWesley Sheng if (reg < stdev->pff_csr_count) 1499080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 1500080b47deSLogan Gunthorpe 1501080b47deSLogan Gunthorpe reg = ioread32(&pcfg->vep_pff_inst_id); 15027501a02aSWesley Sheng if (reg < stdev->pff_csr_count) 1503080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 1504080b47deSLogan Gunthorpe 1505080b47deSLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(pcfg->dsp_pff_inst_id); i++) { 1506080b47deSLogan Gunthorpe reg = ioread32(&pcfg->dsp_pff_inst_id[i]); 15077501a02aSWesley Sheng if (reg < stdev->pff_csr_count) 1508080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 1509080b47deSLogan Gunthorpe } 1510080b47deSLogan Gunthorpe } 1511080b47deSLogan Gunthorpe 1512080b47deSLogan Gunthorpe static int switchtec_init_pci(struct switchtec_dev *stdev, 1513080b47deSLogan Gunthorpe struct pci_dev *pdev) 1514080b47deSLogan Gunthorpe { 1515080b47deSLogan Gunthorpe int rc; 151652d8db8eSKelvin Cao void __iomem *map; 151752d8db8eSKelvin Cao unsigned long res_start, res_len; 1518993d208dSLogan Gunthorpe u32 __iomem *part_id; 1519080b47deSLogan Gunthorpe 1520080b47deSLogan Gunthorpe rc = pcim_enable_device(pdev); 1521080b47deSLogan Gunthorpe if (rc) 1522080b47deSLogan Gunthorpe return rc; 1523080b47deSLogan Gunthorpe 1524aa82130aSWesley Sheng rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 1525aff614c6SBoris Glimcher if (rc) 1526aff614c6SBoris Glimcher return rc; 1527aff614c6SBoris Glimcher 1528080b47deSLogan Gunthorpe pci_set_master(pdev); 1529080b47deSLogan Gunthorpe 153052d8db8eSKelvin Cao res_start = pci_resource_start(pdev, 0); 153152d8db8eSKelvin Cao res_len = pci_resource_len(pdev, 0); 153252d8db8eSKelvin Cao 153352d8db8eSKelvin Cao if (!devm_request_mem_region(&pdev->dev, res_start, 153452d8db8eSKelvin Cao res_len, KBUILD_MODNAME)) 153552d8db8eSKelvin Cao return -EBUSY; 153652d8db8eSKelvin Cao 153752d8db8eSKelvin Cao stdev->mmio_mrpc = devm_ioremap_wc(&pdev->dev, res_start, 153852d8db8eSKelvin Cao SWITCHTEC_GAS_TOP_CFG_OFFSET); 153952d8db8eSKelvin Cao if (!stdev->mmio_mrpc) 154052d8db8eSKelvin Cao return -ENOMEM; 154152d8db8eSKelvin Cao 154252d8db8eSKelvin Cao map = devm_ioremap(&pdev->dev, 154352d8db8eSKelvin Cao res_start + SWITCHTEC_GAS_TOP_CFG_OFFSET, 154452d8db8eSKelvin Cao res_len - SWITCHTEC_GAS_TOP_CFG_OFFSET); 154552d8db8eSKelvin Cao if (!map) 154652d8db8eSKelvin Cao return -ENOMEM; 154752d8db8eSKelvin Cao 154852d8db8eSKelvin Cao stdev->mmio = map - SWITCHTEC_GAS_TOP_CFG_OFFSET; 1549080b47deSLogan Gunthorpe stdev->mmio_sw_event = stdev->mmio + SWITCHTEC_GAS_SW_EVENT_OFFSET; 1550080b47deSLogan Gunthorpe stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET; 1551080b47deSLogan Gunthorpe stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET; 1552080b47deSLogan Gunthorpe stdev->mmio_ntb = stdev->mmio + SWITCHTEC_GAS_NTB_OFFSET; 1553993d208dSLogan Gunthorpe 1554993d208dSLogan Gunthorpe if (stdev->gen == SWITCHTEC_GEN3) 1555993d208dSLogan Gunthorpe part_id = &stdev->mmio_sys_info->gen3.partition_id; 1556a3321ca3SLogan Gunthorpe else if (stdev->gen == SWITCHTEC_GEN4) 1557a3321ca3SLogan Gunthorpe part_id = &stdev->mmio_sys_info->gen4.partition_id; 1558993d208dSLogan Gunthorpe else 1559993d208dSLogan Gunthorpe return -ENOTSUPP; 1560993d208dSLogan Gunthorpe 1561993d208dSLogan Gunthorpe stdev->partition = ioread8(part_id); 1562080b47deSLogan Gunthorpe stdev->partition_count = ioread8(&stdev->mmio_ntb->partition_count); 1563080b47deSLogan Gunthorpe stdev->mmio_part_cfg_all = stdev->mmio + SWITCHTEC_GAS_PART_CFG_OFFSET; 1564080b47deSLogan Gunthorpe stdev->mmio_part_cfg = &stdev->mmio_part_cfg_all[stdev->partition]; 1565080b47deSLogan Gunthorpe stdev->mmio_pff_csr = stdev->mmio + SWITCHTEC_GAS_PFF_CSR_OFFSET; 1566080b47deSLogan Gunthorpe 15679871e9bbSLogan Gunthorpe if (stdev->partition_count < 1) 15689871e9bbSLogan Gunthorpe stdev->partition_count = 1; 15699871e9bbSLogan Gunthorpe 1570080b47deSLogan Gunthorpe init_pff(stdev); 1571080b47deSLogan Gunthorpe 1572080b47deSLogan Gunthorpe pci_set_drvdata(pdev, stdev); 1573080b47deSLogan Gunthorpe 1574f7eb7b8aSWesley Sheng if (!use_dma_mrpc) 1575f7eb7b8aSWesley Sheng return 0; 1576f7eb7b8aSWesley Sheng 1577f7eb7b8aSWesley Sheng if (ioread32(&stdev->mmio_mrpc->dma_ver) == 0) 1578f7eb7b8aSWesley Sheng return 0; 1579f7eb7b8aSWesley Sheng 1580750afb08SLuis Chamberlain stdev->dma_mrpc = dma_alloc_coherent(&stdev->pdev->dev, 1581f7eb7b8aSWesley Sheng sizeof(*stdev->dma_mrpc), 1582f7eb7b8aSWesley Sheng &stdev->dma_mrpc_dma_addr, 1583f7eb7b8aSWesley Sheng GFP_KERNEL); 1584f7eb7b8aSWesley Sheng if (stdev->dma_mrpc == NULL) 1585f7eb7b8aSWesley Sheng return -ENOMEM; 1586f7eb7b8aSWesley Sheng 1587080b47deSLogan Gunthorpe return 0; 1588080b47deSLogan Gunthorpe } 1589080b47deSLogan Gunthorpe 1590080b47deSLogan Gunthorpe static int switchtec_pci_probe(struct pci_dev *pdev, 1591080b47deSLogan Gunthorpe const struct pci_device_id *id) 1592080b47deSLogan Gunthorpe { 1593080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 1594080b47deSLogan Gunthorpe int rc; 1595080b47deSLogan Gunthorpe 1596cfdfc14eSDoug Meyer if (pdev->class == (PCI_CLASS_BRIDGE_OTHER << 8)) 159733dea5aaSLogan Gunthorpe request_module_nowait("ntb_hw_switchtec"); 159833dea5aaSLogan Gunthorpe 1599080b47deSLogan Gunthorpe stdev = stdev_create(pdev); 1600080b47deSLogan Gunthorpe if (IS_ERR(stdev)) 1601080b47deSLogan Gunthorpe return PTR_ERR(stdev); 1602080b47deSLogan Gunthorpe 1603b13313a0SLogan Gunthorpe stdev->gen = id->driver_data; 1604b13313a0SLogan Gunthorpe 1605080b47deSLogan Gunthorpe rc = switchtec_init_pci(stdev, pdev); 1606080b47deSLogan Gunthorpe if (rc) 1607080b47deSLogan Gunthorpe goto err_put; 1608080b47deSLogan Gunthorpe 1609080b47deSLogan Gunthorpe rc = switchtec_init_isr(stdev); 1610080b47deSLogan Gunthorpe if (rc) { 1611080b47deSLogan Gunthorpe dev_err(&stdev->dev, "failed to init isr.\n"); 1612080b47deSLogan Gunthorpe goto err_put; 1613080b47deSLogan Gunthorpe } 1614080b47deSLogan Gunthorpe 1615080b47deSLogan Gunthorpe iowrite32(SWITCHTEC_EVENT_CLEAR | 1616080b47deSLogan Gunthorpe SWITCHTEC_EVENT_EN_IRQ, 1617080b47deSLogan Gunthorpe &stdev->mmio_part_cfg->mrpc_comp_hdr); 161848c302dcSLogan Gunthorpe enable_link_state_events(stdev); 1619080b47deSLogan Gunthorpe 1620f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) 1621f7eb7b8aSWesley Sheng enable_dma_mrpc(stdev); 1622f7eb7b8aSWesley Sheng 1623e40cf640SLogan Gunthorpe rc = cdev_device_add(&stdev->cdev, &stdev->dev); 1624080b47deSLogan Gunthorpe if (rc) 1625080b47deSLogan Gunthorpe goto err_devadd; 1626080b47deSLogan Gunthorpe 1627080b47deSLogan Gunthorpe dev_info(&stdev->dev, "Management device registered.\n"); 1628080b47deSLogan Gunthorpe 1629080b47deSLogan Gunthorpe return 0; 1630080b47deSLogan Gunthorpe 1631080b47deSLogan Gunthorpe err_devadd: 1632080b47deSLogan Gunthorpe stdev_kill(stdev); 1633080b47deSLogan Gunthorpe err_put: 1634080b47deSLogan Gunthorpe ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); 1635080b47deSLogan Gunthorpe put_device(&stdev->dev); 1636080b47deSLogan Gunthorpe return rc; 1637080b47deSLogan Gunthorpe } 1638080b47deSLogan Gunthorpe 1639080b47deSLogan Gunthorpe static void switchtec_pci_remove(struct pci_dev *pdev) 1640080b47deSLogan Gunthorpe { 1641080b47deSLogan Gunthorpe struct switchtec_dev *stdev = pci_get_drvdata(pdev); 1642080b47deSLogan Gunthorpe 1643080b47deSLogan Gunthorpe pci_set_drvdata(pdev, NULL); 1644080b47deSLogan Gunthorpe 1645e40cf640SLogan Gunthorpe cdev_device_del(&stdev->cdev, &stdev->dev); 1646080b47deSLogan Gunthorpe ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); 1647080b47deSLogan Gunthorpe dev_info(&stdev->dev, "unregistered.\n"); 1648080b47deSLogan Gunthorpe stdev_kill(stdev); 1649080b47deSLogan Gunthorpe put_device(&stdev->dev); 1650080b47deSLogan Gunthorpe } 1651080b47deSLogan Gunthorpe 1652b13313a0SLogan Gunthorpe #define SWITCHTEC_PCI_DEVICE(device_id, gen) \ 1653080b47deSLogan Gunthorpe { \ 1654cfdfc14eSDoug Meyer .vendor = PCI_VENDOR_ID_MICROSEMI, \ 1655080b47deSLogan Gunthorpe .device = device_id, \ 1656080b47deSLogan Gunthorpe .subvendor = PCI_ANY_ID, \ 1657080b47deSLogan Gunthorpe .subdevice = PCI_ANY_ID, \ 1658cfdfc14eSDoug Meyer .class = (PCI_CLASS_MEMORY_OTHER << 8), \ 1659080b47deSLogan Gunthorpe .class_mask = 0xFFFFFFFF, \ 1660b13313a0SLogan Gunthorpe .driver_data = gen, \ 1661080b47deSLogan Gunthorpe }, \ 1662080b47deSLogan Gunthorpe { \ 1663cfdfc14eSDoug Meyer .vendor = PCI_VENDOR_ID_MICROSEMI, \ 1664080b47deSLogan Gunthorpe .device = device_id, \ 1665080b47deSLogan Gunthorpe .subvendor = PCI_ANY_ID, \ 1666080b47deSLogan Gunthorpe .subdevice = PCI_ANY_ID, \ 1667cfdfc14eSDoug Meyer .class = (PCI_CLASS_BRIDGE_OTHER << 8), \ 1668080b47deSLogan Gunthorpe .class_mask = 0xFFFFFFFF, \ 1669b13313a0SLogan Gunthorpe .driver_data = gen, \ 1670080b47deSLogan Gunthorpe } 1671080b47deSLogan Gunthorpe 1672080b47deSLogan Gunthorpe static const struct pci_device_id switchtec_pci_tbl[] = { 1673b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8531, SWITCHTEC_GEN3), //PFX 24xG3 1674b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8532, SWITCHTEC_GEN3), //PFX 32xG3 1675b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8533, SWITCHTEC_GEN3), //PFX 48xG3 1676b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8534, SWITCHTEC_GEN3), //PFX 64xG3 1677b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8535, SWITCHTEC_GEN3), //PFX 80xG3 1678b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8536, SWITCHTEC_GEN3), //PFX 96xG3 1679b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8541, SWITCHTEC_GEN3), //PSX 24xG3 1680b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8542, SWITCHTEC_GEN3), //PSX 32xG3 1681b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8543, SWITCHTEC_GEN3), //PSX 48xG3 1682b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8544, SWITCHTEC_GEN3), //PSX 64xG3 1683b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8545, SWITCHTEC_GEN3), //PSX 80xG3 1684b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8546, SWITCHTEC_GEN3), //PSX 96xG3 1685b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8551, SWITCHTEC_GEN3), //PAX 24XG3 1686b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8552, SWITCHTEC_GEN3), //PAX 32XG3 1687b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8553, SWITCHTEC_GEN3), //PAX 48XG3 1688b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8554, SWITCHTEC_GEN3), //PAX 64XG3 1689b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8555, SWITCHTEC_GEN3), //PAX 80XG3 1690b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8556, SWITCHTEC_GEN3), //PAX 96XG3 1691b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8561, SWITCHTEC_GEN3), //PFXL 24XG3 1692b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8562, SWITCHTEC_GEN3), //PFXL 32XG3 1693b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8563, SWITCHTEC_GEN3), //PFXL 48XG3 1694b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8564, SWITCHTEC_GEN3), //PFXL 64XG3 1695b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8565, SWITCHTEC_GEN3), //PFXL 80XG3 1696b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8566, SWITCHTEC_GEN3), //PFXL 96XG3 1697b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8571, SWITCHTEC_GEN3), //PFXI 24XG3 1698b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8572, SWITCHTEC_GEN3), //PFXI 32XG3 1699b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8573, SWITCHTEC_GEN3), //PFXI 48XG3 1700b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8574, SWITCHTEC_GEN3), //PFXI 64XG3 1701b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8575, SWITCHTEC_GEN3), //PFXI 80XG3 1702b13313a0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8576, SWITCHTEC_GEN3), //PFXI 96XG3 17037a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4000, SWITCHTEC_GEN4), //PFX 100XG4 17047a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4084, SWITCHTEC_GEN4), //PFX 84XG4 17057a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4068, SWITCHTEC_GEN4), //PFX 68XG4 17067a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4052, SWITCHTEC_GEN4), //PFX 52XG4 17077a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4036, SWITCHTEC_GEN4), //PFX 36XG4 17087a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4028, SWITCHTEC_GEN4), //PFX 28XG4 17097a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4100, SWITCHTEC_GEN4), //PSX 100XG4 17107a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4184, SWITCHTEC_GEN4), //PSX 84XG4 17117a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4168, SWITCHTEC_GEN4), //PSX 68XG4 17127a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4152, SWITCHTEC_GEN4), //PSX 52XG4 17137a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4136, SWITCHTEC_GEN4), //PSX 36XG4 17147a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4128, SWITCHTEC_GEN4), //PSX 28XG4 17157a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4200, SWITCHTEC_GEN4), //PAX 100XG4 17167a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4284, SWITCHTEC_GEN4), //PAX 84XG4 17177a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4268, SWITCHTEC_GEN4), //PAX 68XG4 17187a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4252, SWITCHTEC_GEN4), //PAX 52XG4 17197a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4236, SWITCHTEC_GEN4), //PAX 36XG4 17207a30ebb9SKelvin Cao SWITCHTEC_PCI_DEVICE(0x4228, SWITCHTEC_GEN4), //PAX 28XG4 1721080b47deSLogan Gunthorpe {0} 1722080b47deSLogan Gunthorpe }; 1723080b47deSLogan Gunthorpe MODULE_DEVICE_TABLE(pci, switchtec_pci_tbl); 1724080b47deSLogan Gunthorpe 1725080b47deSLogan Gunthorpe static struct pci_driver switchtec_pci_driver = { 1726080b47deSLogan Gunthorpe .name = KBUILD_MODNAME, 1727080b47deSLogan Gunthorpe .id_table = switchtec_pci_tbl, 1728080b47deSLogan Gunthorpe .probe = switchtec_pci_probe, 1729080b47deSLogan Gunthorpe .remove = switchtec_pci_remove, 1730080b47deSLogan Gunthorpe }; 1731080b47deSLogan Gunthorpe 1732080b47deSLogan Gunthorpe static int __init switchtec_init(void) 1733080b47deSLogan Gunthorpe { 1734080b47deSLogan Gunthorpe int rc; 1735080b47deSLogan Gunthorpe 1736080b47deSLogan Gunthorpe rc = alloc_chrdev_region(&switchtec_devt, 0, max_devices, 1737080b47deSLogan Gunthorpe "switchtec"); 1738080b47deSLogan Gunthorpe if (rc) 1739080b47deSLogan Gunthorpe return rc; 1740080b47deSLogan Gunthorpe 1741080b47deSLogan Gunthorpe switchtec_class = class_create(THIS_MODULE, "switchtec"); 1742080b47deSLogan Gunthorpe if (IS_ERR(switchtec_class)) { 1743080b47deSLogan Gunthorpe rc = PTR_ERR(switchtec_class); 1744080b47deSLogan Gunthorpe goto err_create_class; 1745080b47deSLogan Gunthorpe } 1746080b47deSLogan Gunthorpe 1747080b47deSLogan Gunthorpe rc = pci_register_driver(&switchtec_pci_driver); 1748080b47deSLogan Gunthorpe if (rc) 1749080b47deSLogan Gunthorpe goto err_pci_register; 1750080b47deSLogan Gunthorpe 1751080b47deSLogan Gunthorpe pr_info(KBUILD_MODNAME ": loaded.\n"); 1752080b47deSLogan Gunthorpe 1753080b47deSLogan Gunthorpe return 0; 1754080b47deSLogan Gunthorpe 1755080b47deSLogan Gunthorpe err_pci_register: 1756080b47deSLogan Gunthorpe class_destroy(switchtec_class); 1757080b47deSLogan Gunthorpe 1758080b47deSLogan Gunthorpe err_create_class: 1759080b47deSLogan Gunthorpe unregister_chrdev_region(switchtec_devt, max_devices); 1760080b47deSLogan Gunthorpe 1761080b47deSLogan Gunthorpe return rc; 1762080b47deSLogan Gunthorpe } 1763080b47deSLogan Gunthorpe module_init(switchtec_init); 1764080b47deSLogan Gunthorpe 1765080b47deSLogan Gunthorpe static void __exit switchtec_exit(void) 1766080b47deSLogan Gunthorpe { 1767080b47deSLogan Gunthorpe pci_unregister_driver(&switchtec_pci_driver); 1768080b47deSLogan Gunthorpe class_destroy(switchtec_class); 1769080b47deSLogan Gunthorpe unregister_chrdev_region(switchtec_devt, max_devices); 1770080b47deSLogan Gunthorpe ida_destroy(&switchtec_minor_ida); 1771080b47deSLogan Gunthorpe 1772080b47deSLogan Gunthorpe pr_info(KBUILD_MODNAME ": unloaded.\n"); 1773080b47deSLogan Gunthorpe } 1774080b47deSLogan Gunthorpe module_exit(switchtec_exit); 1775