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 28f7eb7b8aSWesley Sheng static bool use_dma_mrpc = 1; 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 33080b47deSLogan Gunthorpe static dev_t switchtec_devt; 34080b47deSLogan Gunthorpe static DEFINE_IDA(switchtec_minor_ida); 35080b47deSLogan Gunthorpe 36302e994dSLogan Gunthorpe struct class *switchtec_class; 37302e994dSLogan Gunthorpe EXPORT_SYMBOL_GPL(switchtec_class); 38080b47deSLogan Gunthorpe 39080b47deSLogan Gunthorpe enum mrpc_state { 40080b47deSLogan Gunthorpe MRPC_IDLE = 0, 41080b47deSLogan Gunthorpe MRPC_QUEUED, 42080b47deSLogan Gunthorpe MRPC_RUNNING, 43080b47deSLogan Gunthorpe MRPC_DONE, 44080b47deSLogan Gunthorpe }; 45080b47deSLogan Gunthorpe 46080b47deSLogan Gunthorpe struct switchtec_user { 47080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 48080b47deSLogan Gunthorpe 49080b47deSLogan Gunthorpe enum mrpc_state state; 50080b47deSLogan Gunthorpe 51080b47deSLogan Gunthorpe struct completion comp; 52080b47deSLogan Gunthorpe struct kref kref; 53080b47deSLogan Gunthorpe struct list_head list; 54080b47deSLogan Gunthorpe 55080b47deSLogan Gunthorpe u32 cmd; 56080b47deSLogan Gunthorpe u32 status; 57080b47deSLogan Gunthorpe u32 return_code; 58080b47deSLogan Gunthorpe size_t data_len; 59080b47deSLogan Gunthorpe size_t read_len; 60080b47deSLogan Gunthorpe unsigned char data[SWITCHTEC_MRPC_PAYLOAD_SIZE]; 61080b47deSLogan Gunthorpe int event_cnt; 62080b47deSLogan Gunthorpe }; 63080b47deSLogan Gunthorpe 64080b47deSLogan Gunthorpe static struct switchtec_user *stuser_create(struct switchtec_dev *stdev) 65080b47deSLogan Gunthorpe { 66080b47deSLogan Gunthorpe struct switchtec_user *stuser; 67080b47deSLogan Gunthorpe 68080b47deSLogan Gunthorpe stuser = kzalloc(sizeof(*stuser), GFP_KERNEL); 69080b47deSLogan Gunthorpe if (!stuser) 70080b47deSLogan Gunthorpe return ERR_PTR(-ENOMEM); 71080b47deSLogan Gunthorpe 72080b47deSLogan Gunthorpe get_device(&stdev->dev); 73080b47deSLogan Gunthorpe stuser->stdev = stdev; 74080b47deSLogan Gunthorpe kref_init(&stuser->kref); 75080b47deSLogan Gunthorpe INIT_LIST_HEAD(&stuser->list); 76080b47deSLogan Gunthorpe init_completion(&stuser->comp); 77080b47deSLogan Gunthorpe stuser->event_cnt = atomic_read(&stdev->event_cnt); 78080b47deSLogan Gunthorpe 79080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser); 80080b47deSLogan Gunthorpe 81080b47deSLogan Gunthorpe return stuser; 82080b47deSLogan Gunthorpe } 83080b47deSLogan Gunthorpe 84080b47deSLogan Gunthorpe static void stuser_free(struct kref *kref) 85080b47deSLogan Gunthorpe { 86080b47deSLogan Gunthorpe struct switchtec_user *stuser; 87080b47deSLogan Gunthorpe 88080b47deSLogan Gunthorpe stuser = container_of(kref, struct switchtec_user, kref); 89080b47deSLogan Gunthorpe 90080b47deSLogan Gunthorpe dev_dbg(&stuser->stdev->dev, "%s: %p\n", __func__, stuser); 91080b47deSLogan Gunthorpe 92080b47deSLogan Gunthorpe put_device(&stuser->stdev->dev); 93080b47deSLogan Gunthorpe kfree(stuser); 94080b47deSLogan Gunthorpe } 95080b47deSLogan Gunthorpe 96080b47deSLogan Gunthorpe static void stuser_put(struct switchtec_user *stuser) 97080b47deSLogan Gunthorpe { 98080b47deSLogan Gunthorpe kref_put(&stuser->kref, stuser_free); 99080b47deSLogan Gunthorpe } 100080b47deSLogan Gunthorpe 101080b47deSLogan Gunthorpe static void stuser_set_state(struct switchtec_user *stuser, 102080b47deSLogan Gunthorpe enum mrpc_state state) 103080b47deSLogan Gunthorpe { 104080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 105080b47deSLogan Gunthorpe 106080b47deSLogan Gunthorpe const char * const state_names[] = { 107080b47deSLogan Gunthorpe [MRPC_IDLE] = "IDLE", 108080b47deSLogan Gunthorpe [MRPC_QUEUED] = "QUEUED", 109080b47deSLogan Gunthorpe [MRPC_RUNNING] = "RUNNING", 110080b47deSLogan Gunthorpe [MRPC_DONE] = "DONE", 111080b47deSLogan Gunthorpe }; 112080b47deSLogan Gunthorpe 113080b47deSLogan Gunthorpe stuser->state = state; 114080b47deSLogan Gunthorpe 115080b47deSLogan Gunthorpe dev_dbg(&stuser->stdev->dev, "stuser state %p -> %s", 116080b47deSLogan Gunthorpe stuser, state_names[state]); 117080b47deSLogan Gunthorpe } 118080b47deSLogan Gunthorpe 119080b47deSLogan Gunthorpe static void mrpc_complete_cmd(struct switchtec_dev *stdev); 120080b47deSLogan Gunthorpe 12152d8db8eSKelvin Cao static void flush_wc_buf(struct switchtec_dev *stdev) 12252d8db8eSKelvin Cao { 12352d8db8eSKelvin Cao struct ntb_dbmsg_regs __iomem *mmio_dbmsg; 12452d8db8eSKelvin Cao 12552d8db8eSKelvin Cao /* 12652d8db8eSKelvin Cao * odb (outbound doorbell) register is processed by low latency 12752d8db8eSKelvin Cao * hardware and w/o side effect 12852d8db8eSKelvin Cao */ 12952d8db8eSKelvin Cao mmio_dbmsg = (void __iomem *)stdev->mmio_ntb + 13052d8db8eSKelvin Cao SWITCHTEC_NTB_REG_DBMSG_OFFSET; 13152d8db8eSKelvin Cao ioread32(&mmio_dbmsg->odb); 13252d8db8eSKelvin Cao } 13352d8db8eSKelvin Cao 134080b47deSLogan Gunthorpe static void mrpc_cmd_submit(struct switchtec_dev *stdev) 135080b47deSLogan Gunthorpe { 136080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 137080b47deSLogan Gunthorpe 138080b47deSLogan Gunthorpe struct switchtec_user *stuser; 139080b47deSLogan Gunthorpe 140080b47deSLogan Gunthorpe if (stdev->mrpc_busy) 141080b47deSLogan Gunthorpe return; 142080b47deSLogan Gunthorpe 143080b47deSLogan Gunthorpe if (list_empty(&stdev->mrpc_queue)) 144080b47deSLogan Gunthorpe return; 145080b47deSLogan Gunthorpe 146080b47deSLogan Gunthorpe stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, 147080b47deSLogan Gunthorpe list); 148080b47deSLogan Gunthorpe 149f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) { 150f7eb7b8aSWesley Sheng stdev->dma_mrpc->status = SWITCHTEC_MRPC_STATUS_INPROGRESS; 151f7eb7b8aSWesley Sheng memset(stdev->dma_mrpc->data, 0xFF, SWITCHTEC_MRPC_PAYLOAD_SIZE); 152f7eb7b8aSWesley Sheng } 153f7eb7b8aSWesley Sheng 154080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_RUNNING); 155080b47deSLogan Gunthorpe stdev->mrpc_busy = 1; 156080b47deSLogan Gunthorpe memcpy_toio(&stdev->mmio_mrpc->input_data, 157080b47deSLogan Gunthorpe stuser->data, stuser->data_len); 15852d8db8eSKelvin Cao flush_wc_buf(stdev); 159080b47deSLogan Gunthorpe iowrite32(stuser->cmd, &stdev->mmio_mrpc->cmd); 160080b47deSLogan Gunthorpe 161080b47deSLogan Gunthorpe schedule_delayed_work(&stdev->mrpc_timeout, 162080b47deSLogan Gunthorpe msecs_to_jiffies(500)); 163080b47deSLogan Gunthorpe } 164080b47deSLogan Gunthorpe 165080b47deSLogan Gunthorpe static int mrpc_queue_cmd(struct switchtec_user *stuser) 166080b47deSLogan Gunthorpe { 167080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 168080b47deSLogan Gunthorpe 169080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 170080b47deSLogan Gunthorpe 171080b47deSLogan Gunthorpe kref_get(&stuser->kref); 172080b47deSLogan Gunthorpe stuser->read_len = sizeof(stuser->data); 173080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_QUEUED); 174080b47deSLogan Gunthorpe init_completion(&stuser->comp); 175080b47deSLogan Gunthorpe list_add_tail(&stuser->list, &stdev->mrpc_queue); 176080b47deSLogan Gunthorpe 177080b47deSLogan Gunthorpe mrpc_cmd_submit(stdev); 178080b47deSLogan Gunthorpe 179080b47deSLogan Gunthorpe return 0; 180080b47deSLogan Gunthorpe } 181080b47deSLogan Gunthorpe 182080b47deSLogan Gunthorpe static void mrpc_complete_cmd(struct switchtec_dev *stdev) 183080b47deSLogan Gunthorpe { 184080b47deSLogan Gunthorpe /* requires the mrpc_mutex to already be held when called */ 185080b47deSLogan Gunthorpe struct switchtec_user *stuser; 186080b47deSLogan Gunthorpe 187080b47deSLogan Gunthorpe if (list_empty(&stdev->mrpc_queue)) 188080b47deSLogan Gunthorpe return; 189080b47deSLogan Gunthorpe 190080b47deSLogan Gunthorpe stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user, 191080b47deSLogan Gunthorpe list); 192080b47deSLogan Gunthorpe 193f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) 194f7eb7b8aSWesley Sheng stuser->status = stdev->dma_mrpc->status; 195f7eb7b8aSWesley Sheng else 196080b47deSLogan Gunthorpe stuser->status = ioread32(&stdev->mmio_mrpc->status); 197f7eb7b8aSWesley Sheng 198080b47deSLogan Gunthorpe if (stuser->status == SWITCHTEC_MRPC_STATUS_INPROGRESS) 199080b47deSLogan Gunthorpe return; 200080b47deSLogan Gunthorpe 201080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_DONE); 202080b47deSLogan Gunthorpe stuser->return_code = 0; 203080b47deSLogan Gunthorpe 204080b47deSLogan Gunthorpe if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE) 205080b47deSLogan Gunthorpe goto out; 206080b47deSLogan Gunthorpe 207f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) 208f7eb7b8aSWesley Sheng stuser->return_code = stdev->dma_mrpc->rtn_code; 209f7eb7b8aSWesley Sheng else 210080b47deSLogan Gunthorpe stuser->return_code = ioread32(&stdev->mmio_mrpc->ret_value); 211080b47deSLogan Gunthorpe if (stuser->return_code != 0) 212080b47deSLogan Gunthorpe goto out; 213080b47deSLogan Gunthorpe 214f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) 215f7eb7b8aSWesley Sheng memcpy(stuser->data, &stdev->dma_mrpc->data, 216f7eb7b8aSWesley Sheng stuser->read_len); 217f7eb7b8aSWesley Sheng else 218080b47deSLogan Gunthorpe memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data, 219080b47deSLogan Gunthorpe stuser->read_len); 220080b47deSLogan Gunthorpe out: 221080b47deSLogan Gunthorpe complete_all(&stuser->comp); 222080b47deSLogan Gunthorpe list_del_init(&stuser->list); 223080b47deSLogan Gunthorpe stuser_put(stuser); 224080b47deSLogan Gunthorpe stdev->mrpc_busy = 0; 225080b47deSLogan Gunthorpe 226080b47deSLogan Gunthorpe mrpc_cmd_submit(stdev); 227080b47deSLogan Gunthorpe } 228080b47deSLogan Gunthorpe 229080b47deSLogan Gunthorpe static void mrpc_event_work(struct work_struct *work) 230080b47deSLogan Gunthorpe { 231080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 232080b47deSLogan Gunthorpe 233080b47deSLogan Gunthorpe stdev = container_of(work, struct switchtec_dev, mrpc_work); 234080b47deSLogan Gunthorpe 235080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s\n", __func__); 236080b47deSLogan Gunthorpe 237080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 238080b47deSLogan Gunthorpe cancel_delayed_work(&stdev->mrpc_timeout); 239080b47deSLogan Gunthorpe mrpc_complete_cmd(stdev); 240080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 241080b47deSLogan Gunthorpe } 242080b47deSLogan Gunthorpe 243080b47deSLogan Gunthorpe static void mrpc_timeout_work(struct work_struct *work) 244080b47deSLogan Gunthorpe { 245080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 246080b47deSLogan Gunthorpe u32 status; 247080b47deSLogan Gunthorpe 248080b47deSLogan Gunthorpe stdev = container_of(work, struct switchtec_dev, mrpc_timeout.work); 249080b47deSLogan Gunthorpe 250080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s\n", __func__); 251080b47deSLogan Gunthorpe 252080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 253080b47deSLogan Gunthorpe 254f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) 255f7eb7b8aSWesley Sheng status = stdev->dma_mrpc->status; 256f7eb7b8aSWesley Sheng else 257080b47deSLogan Gunthorpe status = ioread32(&stdev->mmio_mrpc->status); 258080b47deSLogan Gunthorpe if (status == SWITCHTEC_MRPC_STATUS_INPROGRESS) { 259080b47deSLogan Gunthorpe schedule_delayed_work(&stdev->mrpc_timeout, 260080b47deSLogan Gunthorpe msecs_to_jiffies(500)); 261080b47deSLogan Gunthorpe goto out; 262080b47deSLogan Gunthorpe } 263080b47deSLogan Gunthorpe 264080b47deSLogan Gunthorpe mrpc_complete_cmd(stdev); 265080b47deSLogan Gunthorpe out: 266080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 267080b47deSLogan Gunthorpe } 268080b47deSLogan Gunthorpe 2695d8e1881SLogan Gunthorpe static ssize_t device_version_show(struct device *dev, 2705d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 2715d8e1881SLogan Gunthorpe { 2725d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 2735d8e1881SLogan Gunthorpe u32 ver; 2745d8e1881SLogan Gunthorpe 2755d8e1881SLogan Gunthorpe ver = ioread32(&stdev->mmio_sys_info->device_version); 2765d8e1881SLogan Gunthorpe 2775d8e1881SLogan Gunthorpe return sprintf(buf, "%x\n", ver); 2785d8e1881SLogan Gunthorpe } 2795d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(device_version); 2805d8e1881SLogan Gunthorpe 2815d8e1881SLogan Gunthorpe static ssize_t fw_version_show(struct device *dev, 2825d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 2835d8e1881SLogan Gunthorpe { 2845d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 2855d8e1881SLogan Gunthorpe u32 ver; 2865d8e1881SLogan Gunthorpe 2875d8e1881SLogan Gunthorpe ver = ioread32(&stdev->mmio_sys_info->firmware_version); 2885d8e1881SLogan Gunthorpe 2895d8e1881SLogan Gunthorpe return sprintf(buf, "%08x\n", ver); 2905d8e1881SLogan Gunthorpe } 2915d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(fw_version); 2925d8e1881SLogan Gunthorpe 2935d8e1881SLogan Gunthorpe static ssize_t io_string_show(char *buf, void __iomem *attr, size_t len) 2945d8e1881SLogan Gunthorpe { 2955d8e1881SLogan Gunthorpe int i; 2965d8e1881SLogan Gunthorpe 2975d8e1881SLogan Gunthorpe memcpy_fromio(buf, attr, len); 2985d8e1881SLogan Gunthorpe buf[len] = '\n'; 2995d8e1881SLogan Gunthorpe buf[len + 1] = 0; 3005d8e1881SLogan Gunthorpe 3015d8e1881SLogan Gunthorpe for (i = len - 1; i > 0; i--) { 3025d8e1881SLogan Gunthorpe if (buf[i] != ' ') 3035d8e1881SLogan Gunthorpe break; 3045d8e1881SLogan Gunthorpe buf[i] = '\n'; 3055d8e1881SLogan Gunthorpe buf[i + 1] = 0; 3065d8e1881SLogan Gunthorpe } 3075d8e1881SLogan Gunthorpe 3085d8e1881SLogan Gunthorpe return strlen(buf); 3095d8e1881SLogan Gunthorpe } 3105d8e1881SLogan Gunthorpe 3115d8e1881SLogan Gunthorpe #define DEVICE_ATTR_SYS_INFO_STR(field) \ 3125d8e1881SLogan Gunthorpe static ssize_t field ## _show(struct device *dev, \ 3135d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) \ 3145d8e1881SLogan Gunthorpe { \ 3155d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); \ 3165d8e1881SLogan Gunthorpe return io_string_show(buf, &stdev->mmio_sys_info->field, \ 3175d8e1881SLogan Gunthorpe sizeof(stdev->mmio_sys_info->field)); \ 3185d8e1881SLogan Gunthorpe } \ 3195d8e1881SLogan Gunthorpe \ 3205d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(field) 3215d8e1881SLogan Gunthorpe 3225d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(vendor_id); 3235d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(product_id); 3245d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(product_revision); 3255d8e1881SLogan Gunthorpe DEVICE_ATTR_SYS_INFO_STR(component_vendor); 3265d8e1881SLogan Gunthorpe 3275d8e1881SLogan Gunthorpe static ssize_t component_id_show(struct device *dev, 3285d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 3295d8e1881SLogan Gunthorpe { 3305d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 3315d8e1881SLogan Gunthorpe int id = ioread16(&stdev->mmio_sys_info->component_id); 3325d8e1881SLogan Gunthorpe 3335d8e1881SLogan Gunthorpe return sprintf(buf, "PM%04X\n", id); 3345d8e1881SLogan Gunthorpe } 3355d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(component_id); 3365d8e1881SLogan Gunthorpe 3375d8e1881SLogan Gunthorpe static ssize_t component_revision_show(struct device *dev, 3385d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 3395d8e1881SLogan Gunthorpe { 3405d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 3415d8e1881SLogan Gunthorpe int rev = ioread8(&stdev->mmio_sys_info->component_revision); 3425d8e1881SLogan Gunthorpe 3435d8e1881SLogan Gunthorpe return sprintf(buf, "%d\n", rev); 3445d8e1881SLogan Gunthorpe } 3455d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(component_revision); 3465d8e1881SLogan Gunthorpe 3475d8e1881SLogan Gunthorpe static ssize_t partition_show(struct device *dev, 3485d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 3495d8e1881SLogan Gunthorpe { 3505d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 3515d8e1881SLogan Gunthorpe 3525d8e1881SLogan Gunthorpe return sprintf(buf, "%d\n", stdev->partition); 3535d8e1881SLogan Gunthorpe } 3545d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(partition); 3555d8e1881SLogan Gunthorpe 3565d8e1881SLogan Gunthorpe static ssize_t partition_count_show(struct device *dev, 3575d8e1881SLogan Gunthorpe struct device_attribute *attr, char *buf) 3585d8e1881SLogan Gunthorpe { 3595d8e1881SLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 3605d8e1881SLogan Gunthorpe 3615d8e1881SLogan Gunthorpe return sprintf(buf, "%d\n", stdev->partition_count); 3625d8e1881SLogan Gunthorpe } 3635d8e1881SLogan Gunthorpe static DEVICE_ATTR_RO(partition_count); 3645d8e1881SLogan Gunthorpe 3655d8e1881SLogan Gunthorpe static struct attribute *switchtec_device_attrs[] = { 3665d8e1881SLogan Gunthorpe &dev_attr_device_version.attr, 3675d8e1881SLogan Gunthorpe &dev_attr_fw_version.attr, 3685d8e1881SLogan Gunthorpe &dev_attr_vendor_id.attr, 3695d8e1881SLogan Gunthorpe &dev_attr_product_id.attr, 3705d8e1881SLogan Gunthorpe &dev_attr_product_revision.attr, 3715d8e1881SLogan Gunthorpe &dev_attr_component_vendor.attr, 3725d8e1881SLogan Gunthorpe &dev_attr_component_id.attr, 3735d8e1881SLogan Gunthorpe &dev_attr_component_revision.attr, 3745d8e1881SLogan Gunthorpe &dev_attr_partition.attr, 3755d8e1881SLogan Gunthorpe &dev_attr_partition_count.attr, 3765d8e1881SLogan Gunthorpe NULL, 3775d8e1881SLogan Gunthorpe }; 3785d8e1881SLogan Gunthorpe 3795d8e1881SLogan Gunthorpe ATTRIBUTE_GROUPS(switchtec_device); 3805d8e1881SLogan Gunthorpe 381080b47deSLogan Gunthorpe static int switchtec_dev_open(struct inode *inode, struct file *filp) 382080b47deSLogan Gunthorpe { 383080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 384080b47deSLogan Gunthorpe struct switchtec_user *stuser; 385080b47deSLogan Gunthorpe 386080b47deSLogan Gunthorpe stdev = container_of(inode->i_cdev, struct switchtec_dev, cdev); 387080b47deSLogan Gunthorpe 388080b47deSLogan Gunthorpe stuser = stuser_create(stdev); 389080b47deSLogan Gunthorpe if (IS_ERR(stuser)) 390080b47deSLogan Gunthorpe return PTR_ERR(stuser); 391080b47deSLogan Gunthorpe 392080b47deSLogan Gunthorpe filp->private_data = stuser; 393080b47deSLogan Gunthorpe nonseekable_open(inode, filp); 394080b47deSLogan Gunthorpe 395080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser); 396080b47deSLogan Gunthorpe 397080b47deSLogan Gunthorpe return 0; 398080b47deSLogan Gunthorpe } 399080b47deSLogan Gunthorpe 400080b47deSLogan Gunthorpe static int switchtec_dev_release(struct inode *inode, struct file *filp) 401080b47deSLogan Gunthorpe { 402080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 403080b47deSLogan Gunthorpe 404080b47deSLogan Gunthorpe stuser_put(stuser); 405080b47deSLogan Gunthorpe 406080b47deSLogan Gunthorpe return 0; 407080b47deSLogan Gunthorpe } 408080b47deSLogan Gunthorpe 409080b47deSLogan Gunthorpe static int lock_mutex_and_test_alive(struct switchtec_dev *stdev) 410080b47deSLogan Gunthorpe { 411080b47deSLogan Gunthorpe if (mutex_lock_interruptible(&stdev->mrpc_mutex)) 412080b47deSLogan Gunthorpe return -EINTR; 413080b47deSLogan Gunthorpe 414080b47deSLogan Gunthorpe if (!stdev->alive) { 415080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 416080b47deSLogan Gunthorpe return -ENODEV; 417080b47deSLogan Gunthorpe } 418080b47deSLogan Gunthorpe 419080b47deSLogan Gunthorpe return 0; 420080b47deSLogan Gunthorpe } 421080b47deSLogan Gunthorpe 422080b47deSLogan Gunthorpe static ssize_t switchtec_dev_write(struct file *filp, const char __user *data, 423080b47deSLogan Gunthorpe size_t size, loff_t *off) 424080b47deSLogan Gunthorpe { 425080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 426080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 427080b47deSLogan Gunthorpe int rc; 428080b47deSLogan Gunthorpe 429080b47deSLogan Gunthorpe if (size < sizeof(stuser->cmd) || 430080b47deSLogan Gunthorpe size > sizeof(stuser->cmd) + sizeof(stuser->data)) 431080b47deSLogan Gunthorpe return -EINVAL; 432080b47deSLogan Gunthorpe 433080b47deSLogan Gunthorpe stuser->data_len = size - sizeof(stuser->cmd); 434080b47deSLogan Gunthorpe 435080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 436080b47deSLogan Gunthorpe if (rc) 437080b47deSLogan Gunthorpe return rc; 438080b47deSLogan Gunthorpe 439080b47deSLogan Gunthorpe if (stuser->state != MRPC_IDLE) { 440080b47deSLogan Gunthorpe rc = -EBADE; 441080b47deSLogan Gunthorpe goto out; 442080b47deSLogan Gunthorpe } 443080b47deSLogan Gunthorpe 444080b47deSLogan Gunthorpe rc = copy_from_user(&stuser->cmd, data, sizeof(stuser->cmd)); 445080b47deSLogan Gunthorpe if (rc) { 446080b47deSLogan Gunthorpe rc = -EFAULT; 447080b47deSLogan Gunthorpe goto out; 448080b47deSLogan Gunthorpe } 449080b47deSLogan Gunthorpe 450080b47deSLogan Gunthorpe data += sizeof(stuser->cmd); 451080b47deSLogan Gunthorpe rc = copy_from_user(&stuser->data, data, size - sizeof(stuser->cmd)); 452080b47deSLogan Gunthorpe if (rc) { 453080b47deSLogan Gunthorpe rc = -EFAULT; 454080b47deSLogan Gunthorpe goto out; 455080b47deSLogan Gunthorpe } 456080b47deSLogan Gunthorpe 457080b47deSLogan Gunthorpe rc = mrpc_queue_cmd(stuser); 458080b47deSLogan Gunthorpe 459080b47deSLogan Gunthorpe out: 460080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 461080b47deSLogan Gunthorpe 462080b47deSLogan Gunthorpe if (rc) 463080b47deSLogan Gunthorpe return rc; 464080b47deSLogan Gunthorpe 465080b47deSLogan Gunthorpe return size; 466080b47deSLogan Gunthorpe } 467080b47deSLogan Gunthorpe 468080b47deSLogan Gunthorpe static ssize_t switchtec_dev_read(struct file *filp, char __user *data, 469080b47deSLogan Gunthorpe size_t size, loff_t *off) 470080b47deSLogan Gunthorpe { 471080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 472080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 473080b47deSLogan Gunthorpe int rc; 474080b47deSLogan Gunthorpe 475080b47deSLogan Gunthorpe if (size < sizeof(stuser->cmd) || 476080b47deSLogan Gunthorpe size > sizeof(stuser->cmd) + sizeof(stuser->data)) 477080b47deSLogan Gunthorpe return -EINVAL; 478080b47deSLogan Gunthorpe 479080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 480080b47deSLogan Gunthorpe if (rc) 481080b47deSLogan Gunthorpe return rc; 482080b47deSLogan Gunthorpe 483080b47deSLogan Gunthorpe if (stuser->state == MRPC_IDLE) { 484080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 485080b47deSLogan Gunthorpe return -EBADE; 486080b47deSLogan Gunthorpe } 487080b47deSLogan Gunthorpe 488080b47deSLogan Gunthorpe stuser->read_len = size - sizeof(stuser->return_code); 489080b47deSLogan Gunthorpe 490080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 491080b47deSLogan Gunthorpe 492080b47deSLogan Gunthorpe if (filp->f_flags & O_NONBLOCK) { 493080b47deSLogan Gunthorpe if (!try_wait_for_completion(&stuser->comp)) 494080b47deSLogan Gunthorpe return -EAGAIN; 495080b47deSLogan Gunthorpe } else { 496080b47deSLogan Gunthorpe rc = wait_for_completion_interruptible(&stuser->comp); 497080b47deSLogan Gunthorpe if (rc < 0) 498080b47deSLogan Gunthorpe return rc; 499080b47deSLogan Gunthorpe } 500080b47deSLogan Gunthorpe 501080b47deSLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 502080b47deSLogan Gunthorpe if (rc) 503080b47deSLogan Gunthorpe return rc; 504080b47deSLogan Gunthorpe 505080b47deSLogan Gunthorpe if (stuser->state != MRPC_DONE) { 506080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 507080b47deSLogan Gunthorpe return -EBADE; 508080b47deSLogan Gunthorpe } 509080b47deSLogan Gunthorpe 510080b47deSLogan Gunthorpe rc = copy_to_user(data, &stuser->return_code, 511080b47deSLogan Gunthorpe sizeof(stuser->return_code)); 512080b47deSLogan Gunthorpe if (rc) { 513080b47deSLogan Gunthorpe rc = -EFAULT; 514080b47deSLogan Gunthorpe goto out; 515080b47deSLogan Gunthorpe } 516080b47deSLogan Gunthorpe 517080b47deSLogan Gunthorpe data += sizeof(stuser->return_code); 518080b47deSLogan Gunthorpe rc = copy_to_user(data, &stuser->data, 519080b47deSLogan Gunthorpe size - sizeof(stuser->return_code)); 520080b47deSLogan Gunthorpe if (rc) { 521080b47deSLogan Gunthorpe rc = -EFAULT; 522080b47deSLogan Gunthorpe goto out; 523080b47deSLogan Gunthorpe } 524080b47deSLogan Gunthorpe 525080b47deSLogan Gunthorpe stuser_set_state(stuser, MRPC_IDLE); 526080b47deSLogan Gunthorpe 527080b47deSLogan Gunthorpe out: 528080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 529080b47deSLogan Gunthorpe 530080b47deSLogan Gunthorpe if (stuser->status == SWITCHTEC_MRPC_STATUS_DONE) 531080b47deSLogan Gunthorpe return size; 532080b47deSLogan Gunthorpe else if (stuser->status == SWITCHTEC_MRPC_STATUS_INTERRUPTED) 533080b47deSLogan Gunthorpe return -ENXIO; 534080b47deSLogan Gunthorpe else 535080b47deSLogan Gunthorpe return -EBADMSG; 536080b47deSLogan Gunthorpe } 537080b47deSLogan Gunthorpe 538afc9a42bSAl Viro static __poll_t switchtec_dev_poll(struct file *filp, poll_table *wait) 539080b47deSLogan Gunthorpe { 540080b47deSLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 541080b47deSLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 542afc9a42bSAl Viro __poll_t ret = 0; 543080b47deSLogan Gunthorpe 544080b47deSLogan Gunthorpe poll_wait(filp, &stuser->comp.wait, wait); 545080b47deSLogan Gunthorpe poll_wait(filp, &stdev->event_wq, wait); 546080b47deSLogan Gunthorpe 547080b47deSLogan Gunthorpe if (lock_mutex_and_test_alive(stdev)) 548a9a08845SLinus Torvalds return EPOLLIN | EPOLLRDHUP | EPOLLOUT | EPOLLERR | EPOLLHUP; 549080b47deSLogan Gunthorpe 550080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 551080b47deSLogan Gunthorpe 552080b47deSLogan Gunthorpe if (try_wait_for_completion(&stuser->comp)) 553a9a08845SLinus Torvalds ret |= EPOLLIN | EPOLLRDNORM; 554080b47deSLogan Gunthorpe 555080b47deSLogan Gunthorpe if (stuser->event_cnt != atomic_read(&stdev->event_cnt)) 556a9a08845SLinus Torvalds ret |= EPOLLPRI | EPOLLRDBAND; 557080b47deSLogan Gunthorpe 558080b47deSLogan Gunthorpe return ret; 559080b47deSLogan Gunthorpe } 560080b47deSLogan Gunthorpe 56152eabba5SLogan Gunthorpe static int ioctl_flash_info(struct switchtec_dev *stdev, 56252eabba5SLogan Gunthorpe struct switchtec_ioctl_flash_info __user *uinfo) 56352eabba5SLogan Gunthorpe { 56452eabba5SLogan Gunthorpe struct switchtec_ioctl_flash_info info = {0}; 56552eabba5SLogan Gunthorpe struct flash_info_regs __iomem *fi = stdev->mmio_flash_info; 56652eabba5SLogan Gunthorpe 56752eabba5SLogan Gunthorpe info.flash_length = ioread32(&fi->flash_length); 56852eabba5SLogan Gunthorpe info.num_partitions = SWITCHTEC_IOCTL_NUM_PARTITIONS; 56952eabba5SLogan Gunthorpe 57052eabba5SLogan Gunthorpe if (copy_to_user(uinfo, &info, sizeof(info))) 57152eabba5SLogan Gunthorpe return -EFAULT; 57252eabba5SLogan Gunthorpe 57352eabba5SLogan Gunthorpe return 0; 57452eabba5SLogan Gunthorpe } 57552eabba5SLogan Gunthorpe 57652eabba5SLogan Gunthorpe static void set_fw_info_part(struct switchtec_ioctl_flash_part_info *info, 57752eabba5SLogan Gunthorpe struct partition_info __iomem *pi) 57852eabba5SLogan Gunthorpe { 57952eabba5SLogan Gunthorpe info->address = ioread32(&pi->address); 58052eabba5SLogan Gunthorpe info->length = ioread32(&pi->length); 58152eabba5SLogan Gunthorpe } 58252eabba5SLogan Gunthorpe 58352eabba5SLogan Gunthorpe static int ioctl_flash_part_info(struct switchtec_dev *stdev, 58452eabba5SLogan Gunthorpe struct switchtec_ioctl_flash_part_info __user *uinfo) 58552eabba5SLogan Gunthorpe { 58652eabba5SLogan Gunthorpe struct switchtec_ioctl_flash_part_info info = {0}; 58752eabba5SLogan Gunthorpe struct flash_info_regs __iomem *fi = stdev->mmio_flash_info; 588079e3bc5SLogan Gunthorpe struct sys_info_regs __iomem *si = stdev->mmio_sys_info; 58952eabba5SLogan Gunthorpe u32 active_addr = -1; 59052eabba5SLogan Gunthorpe 59152eabba5SLogan Gunthorpe if (copy_from_user(&info, uinfo, sizeof(info))) 59252eabba5SLogan Gunthorpe return -EFAULT; 59352eabba5SLogan Gunthorpe 59452eabba5SLogan Gunthorpe switch (info.flash_partition) { 59552eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_CFG0: 59652eabba5SLogan Gunthorpe active_addr = ioread32(&fi->active_cfg); 59752eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->cfg0); 598079e3bc5SLogan Gunthorpe if (ioread16(&si->cfg_running) == SWITCHTEC_CFG0_RUNNING) 599079e3bc5SLogan Gunthorpe info.active |= SWITCHTEC_IOCTL_PART_RUNNING; 60052eabba5SLogan Gunthorpe break; 60152eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_CFG1: 60252eabba5SLogan Gunthorpe active_addr = ioread32(&fi->active_cfg); 60352eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->cfg1); 604079e3bc5SLogan Gunthorpe if (ioread16(&si->cfg_running) == SWITCHTEC_CFG1_RUNNING) 605079e3bc5SLogan Gunthorpe info.active |= SWITCHTEC_IOCTL_PART_RUNNING; 60652eabba5SLogan Gunthorpe break; 60752eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_IMG0: 60852eabba5SLogan Gunthorpe active_addr = ioread32(&fi->active_img); 60952eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->img0); 610079e3bc5SLogan Gunthorpe if (ioread16(&si->img_running) == SWITCHTEC_IMG0_RUNNING) 611079e3bc5SLogan Gunthorpe info.active |= SWITCHTEC_IOCTL_PART_RUNNING; 61252eabba5SLogan Gunthorpe break; 61352eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_IMG1: 61452eabba5SLogan Gunthorpe active_addr = ioread32(&fi->active_img); 61552eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->img1); 616079e3bc5SLogan Gunthorpe if (ioread16(&si->img_running) == SWITCHTEC_IMG1_RUNNING) 617079e3bc5SLogan Gunthorpe info.active |= SWITCHTEC_IOCTL_PART_RUNNING; 61852eabba5SLogan Gunthorpe break; 61952eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_NVLOG: 62052eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->nvlog); 62152eabba5SLogan Gunthorpe break; 62252eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR0: 62352eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->vendor[0]); 62452eabba5SLogan Gunthorpe break; 62552eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR1: 62652eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->vendor[1]); 62752eabba5SLogan Gunthorpe break; 62852eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR2: 62952eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->vendor[2]); 63052eabba5SLogan Gunthorpe break; 63152eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR3: 63252eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->vendor[3]); 63352eabba5SLogan Gunthorpe break; 63452eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR4: 63552eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->vendor[4]); 63652eabba5SLogan Gunthorpe break; 63752eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR5: 63852eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->vendor[5]); 63952eabba5SLogan Gunthorpe break; 64052eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR6: 64152eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->vendor[6]); 64252eabba5SLogan Gunthorpe break; 64352eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PART_VENDOR7: 64452eabba5SLogan Gunthorpe set_fw_info_part(&info, &fi->vendor[7]); 64552eabba5SLogan Gunthorpe break; 64652eabba5SLogan Gunthorpe default: 64752eabba5SLogan Gunthorpe return -EINVAL; 64852eabba5SLogan Gunthorpe } 64952eabba5SLogan Gunthorpe 65052eabba5SLogan Gunthorpe if (info.address == active_addr) 651079e3bc5SLogan Gunthorpe info.active |= SWITCHTEC_IOCTL_PART_ACTIVE; 65252eabba5SLogan Gunthorpe 65352eabba5SLogan Gunthorpe if (copy_to_user(uinfo, &info, sizeof(info))) 65452eabba5SLogan Gunthorpe return -EFAULT; 65552eabba5SLogan Gunthorpe 65652eabba5SLogan Gunthorpe return 0; 65752eabba5SLogan Gunthorpe } 65852eabba5SLogan Gunthorpe 65952eabba5SLogan Gunthorpe static int ioctl_event_summary(struct switchtec_dev *stdev, 66052eabba5SLogan Gunthorpe struct switchtec_user *stuser, 661*ba8a3982SWesley Sheng struct switchtec_ioctl_event_summary __user *usum, 662*ba8a3982SWesley Sheng size_t size) 66352eabba5SLogan Gunthorpe { 664*ba8a3982SWesley Sheng struct switchtec_ioctl_event_summary *s; 66552eabba5SLogan Gunthorpe int i; 66652eabba5SLogan Gunthorpe u32 reg; 667*ba8a3982SWesley Sheng int ret = 0; 66852eabba5SLogan Gunthorpe 669*ba8a3982SWesley Sheng s = kzalloc(sizeof(*s), GFP_KERNEL); 670*ba8a3982SWesley Sheng if (!s) 671*ba8a3982SWesley Sheng return -ENOMEM; 672*ba8a3982SWesley Sheng 673*ba8a3982SWesley Sheng s->global = ioread32(&stdev->mmio_sw_event->global_summary); 674*ba8a3982SWesley Sheng s->part_bitmap = ioread32(&stdev->mmio_sw_event->part_event_bitmap); 675*ba8a3982SWesley Sheng s->local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary); 67652eabba5SLogan Gunthorpe 67752eabba5SLogan Gunthorpe for (i = 0; i < stdev->partition_count; i++) { 67852eabba5SLogan Gunthorpe reg = ioread32(&stdev->mmio_part_cfg_all[i].part_event_summary); 679*ba8a3982SWesley Sheng s->part[i] = reg; 68052eabba5SLogan Gunthorpe } 68152eabba5SLogan Gunthorpe 68252eabba5SLogan Gunthorpe for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { 68352eabba5SLogan Gunthorpe reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id); 684cfdfc14eSDoug Meyer if (reg != PCI_VENDOR_ID_MICROSEMI) 68552eabba5SLogan Gunthorpe break; 68652eabba5SLogan Gunthorpe 68752eabba5SLogan Gunthorpe reg = ioread32(&stdev->mmio_pff_csr[i].pff_event_summary); 688*ba8a3982SWesley Sheng s->pff[i] = reg; 68952eabba5SLogan Gunthorpe } 69052eabba5SLogan Gunthorpe 691*ba8a3982SWesley Sheng if (copy_to_user(usum, s, size)) { 692*ba8a3982SWesley Sheng ret = -EFAULT; 693*ba8a3982SWesley Sheng goto error_case; 694*ba8a3982SWesley Sheng } 69552eabba5SLogan Gunthorpe 69652eabba5SLogan Gunthorpe stuser->event_cnt = atomic_read(&stdev->event_cnt); 69752eabba5SLogan Gunthorpe 698*ba8a3982SWesley Sheng error_case: 699*ba8a3982SWesley Sheng kfree(s); 700*ba8a3982SWesley Sheng return ret; 70152eabba5SLogan Gunthorpe } 70252eabba5SLogan Gunthorpe 70352eabba5SLogan Gunthorpe static u32 __iomem *global_ev_reg(struct switchtec_dev *stdev, 70452eabba5SLogan Gunthorpe size_t offset, int index) 70552eabba5SLogan Gunthorpe { 70652eabba5SLogan Gunthorpe return (void __iomem *)stdev->mmio_sw_event + offset; 70752eabba5SLogan Gunthorpe } 70852eabba5SLogan Gunthorpe 70952eabba5SLogan Gunthorpe static u32 __iomem *part_ev_reg(struct switchtec_dev *stdev, 71052eabba5SLogan Gunthorpe size_t offset, int index) 71152eabba5SLogan Gunthorpe { 71252eabba5SLogan Gunthorpe return (void __iomem *)&stdev->mmio_part_cfg_all[index] + offset; 71352eabba5SLogan Gunthorpe } 71452eabba5SLogan Gunthorpe 71552eabba5SLogan Gunthorpe static u32 __iomem *pff_ev_reg(struct switchtec_dev *stdev, 71652eabba5SLogan Gunthorpe size_t offset, int index) 71752eabba5SLogan Gunthorpe { 71852eabba5SLogan Gunthorpe return (void __iomem *)&stdev->mmio_pff_csr[index] + offset; 71952eabba5SLogan Gunthorpe } 72052eabba5SLogan Gunthorpe 72152eabba5SLogan Gunthorpe #define EV_GLB(i, r)[i] = {offsetof(struct sw_event_regs, r), global_ev_reg} 72252eabba5SLogan Gunthorpe #define EV_PAR(i, r)[i] = {offsetof(struct part_cfg_regs, r), part_ev_reg} 72352eabba5SLogan Gunthorpe #define EV_PFF(i, r)[i] = {offsetof(struct pff_csr_regs, r), pff_ev_reg} 72452eabba5SLogan Gunthorpe 725f05f7355SColin Ian King static const struct event_reg { 72652eabba5SLogan Gunthorpe size_t offset; 72752eabba5SLogan Gunthorpe u32 __iomem *(*map_reg)(struct switchtec_dev *stdev, 72852eabba5SLogan Gunthorpe size_t offset, int index); 72952eabba5SLogan Gunthorpe } event_regs[] = { 73052eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_STACK_ERROR, stack_error_event_hdr), 73152eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_PPU_ERROR, ppu_error_event_hdr), 73252eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_ISP_ERROR, isp_error_event_hdr), 73352eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_SYS_RESET, sys_reset_event_hdr), 73452eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_EXC, fw_exception_hdr), 73552eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_NMI, fw_nmi_hdr), 73652eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_NON_FATAL, fw_non_fatal_hdr), 73752eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_FATAL, fw_fatal_hdr), 73852eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_TWI_MRPC_COMP, twi_mrpc_comp_hdr), 73952eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_TWI_MRPC_COMP_ASYNC, 74052eabba5SLogan Gunthorpe twi_mrpc_comp_async_hdr), 74152eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_CLI_MRPC_COMP, cli_mrpc_comp_hdr), 74252eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_CLI_MRPC_COMP_ASYNC, 74352eabba5SLogan Gunthorpe cli_mrpc_comp_async_hdr), 74452eabba5SLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_GPIO_INT, gpio_interrupt_hdr), 745f0edce7aSLogan Gunthorpe EV_GLB(SWITCHTEC_IOCTL_EVENT_GFMS, gfms_event_hdr), 74652eabba5SLogan Gunthorpe EV_PAR(SWITCHTEC_IOCTL_EVENT_PART_RESET, part_reset_hdr), 74752eabba5SLogan Gunthorpe EV_PAR(SWITCHTEC_IOCTL_EVENT_MRPC_COMP, mrpc_comp_hdr), 74852eabba5SLogan Gunthorpe EV_PAR(SWITCHTEC_IOCTL_EVENT_MRPC_COMP_ASYNC, mrpc_comp_async_hdr), 74952eabba5SLogan Gunthorpe EV_PAR(SWITCHTEC_IOCTL_EVENT_DYN_PART_BIND_COMP, dyn_binding_hdr), 75052eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_AER_IN_P2P, aer_in_p2p_hdr), 75152eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_AER_IN_VEP, aer_in_vep_hdr), 75252eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_DPC, dpc_hdr), 75352eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_CTS, cts_hdr), 75452eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_HOTPLUG, hotplug_hdr), 75552eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_IER, ier_hdr), 75652eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_THRESH, threshold_hdr), 75752eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_POWER_MGMT, power_mgmt_hdr), 75852eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_TLP_THROTTLING, tlp_throttling_hdr), 75952eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_FORCE_SPEED, force_speed_hdr), 76052eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_CREDIT_TIMEOUT, credit_timeout_hdr), 76152eabba5SLogan Gunthorpe EV_PFF(SWITCHTEC_IOCTL_EVENT_LINK_STATE, link_state_hdr), 76252eabba5SLogan Gunthorpe }; 76352eabba5SLogan Gunthorpe 76452eabba5SLogan Gunthorpe static u32 __iomem *event_hdr_addr(struct switchtec_dev *stdev, 76552eabba5SLogan Gunthorpe int event_id, int index) 76652eabba5SLogan Gunthorpe { 76752eabba5SLogan Gunthorpe size_t off; 76852eabba5SLogan Gunthorpe 76952eabba5SLogan Gunthorpe if (event_id < 0 || event_id >= SWITCHTEC_IOCTL_MAX_EVENTS) 77052eabba5SLogan Gunthorpe return ERR_PTR(-EINVAL); 77152eabba5SLogan Gunthorpe 77252eabba5SLogan Gunthorpe off = event_regs[event_id].offset; 77352eabba5SLogan Gunthorpe 77452eabba5SLogan Gunthorpe if (event_regs[event_id].map_reg == part_ev_reg) { 77552eabba5SLogan Gunthorpe if (index == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX) 77652eabba5SLogan Gunthorpe index = stdev->partition; 77752eabba5SLogan Gunthorpe else if (index < 0 || index >= stdev->partition_count) 77852eabba5SLogan Gunthorpe return ERR_PTR(-EINVAL); 77952eabba5SLogan Gunthorpe } else if (event_regs[event_id].map_reg == pff_ev_reg) { 78052eabba5SLogan Gunthorpe if (index < 0 || index >= stdev->pff_csr_count) 78152eabba5SLogan Gunthorpe return ERR_PTR(-EINVAL); 78252eabba5SLogan Gunthorpe } 78352eabba5SLogan Gunthorpe 78452eabba5SLogan Gunthorpe return event_regs[event_id].map_reg(stdev, off, index); 78552eabba5SLogan Gunthorpe } 78652eabba5SLogan Gunthorpe 78752eabba5SLogan Gunthorpe static int event_ctl(struct switchtec_dev *stdev, 78852eabba5SLogan Gunthorpe struct switchtec_ioctl_event_ctl *ctl) 78952eabba5SLogan Gunthorpe { 79052eabba5SLogan Gunthorpe int i; 79152eabba5SLogan Gunthorpe u32 __iomem *reg; 79252eabba5SLogan Gunthorpe u32 hdr; 79352eabba5SLogan Gunthorpe 79452eabba5SLogan Gunthorpe reg = event_hdr_addr(stdev, ctl->event_id, ctl->index); 79552eabba5SLogan Gunthorpe if (IS_ERR(reg)) 79652eabba5SLogan Gunthorpe return PTR_ERR(reg); 79752eabba5SLogan Gunthorpe 79852eabba5SLogan Gunthorpe hdr = ioread32(reg); 79952eabba5SLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(ctl->data); i++) 80052eabba5SLogan Gunthorpe ctl->data[i] = ioread32(®[i + 1]); 80152eabba5SLogan Gunthorpe 80252eabba5SLogan Gunthorpe ctl->occurred = hdr & SWITCHTEC_EVENT_OCCURRED; 80352eabba5SLogan Gunthorpe ctl->count = (hdr >> 5) & 0xFF; 80452eabba5SLogan Gunthorpe 80552eabba5SLogan Gunthorpe if (!(ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_CLEAR)) 80652eabba5SLogan Gunthorpe hdr &= ~SWITCHTEC_EVENT_CLEAR; 80752eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL) 80852eabba5SLogan Gunthorpe hdr |= SWITCHTEC_EVENT_EN_IRQ; 80952eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_POLL) 81052eabba5SLogan Gunthorpe hdr &= ~SWITCHTEC_EVENT_EN_IRQ; 81152eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_LOG) 81252eabba5SLogan Gunthorpe hdr |= SWITCHTEC_EVENT_EN_LOG; 81352eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_LOG) 81452eabba5SLogan Gunthorpe hdr &= ~SWITCHTEC_EVENT_EN_LOG; 81552eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_CLI) 81652eabba5SLogan Gunthorpe hdr |= SWITCHTEC_EVENT_EN_CLI; 81752eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_CLI) 81852eabba5SLogan Gunthorpe hdr &= ~SWITCHTEC_EVENT_EN_CLI; 81952eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_FATAL) 82052eabba5SLogan Gunthorpe hdr |= SWITCHTEC_EVENT_FATAL; 82152eabba5SLogan Gunthorpe if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_FATAL) 82252eabba5SLogan Gunthorpe hdr &= ~SWITCHTEC_EVENT_FATAL; 82352eabba5SLogan Gunthorpe 82452eabba5SLogan Gunthorpe if (ctl->flags) 82552eabba5SLogan Gunthorpe iowrite32(hdr, reg); 82652eabba5SLogan Gunthorpe 82752eabba5SLogan Gunthorpe ctl->flags = 0; 82852eabba5SLogan Gunthorpe if (hdr & SWITCHTEC_EVENT_EN_IRQ) 82952eabba5SLogan Gunthorpe ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL; 83052eabba5SLogan Gunthorpe if (hdr & SWITCHTEC_EVENT_EN_LOG) 83152eabba5SLogan Gunthorpe ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_LOG; 83252eabba5SLogan Gunthorpe if (hdr & SWITCHTEC_EVENT_EN_CLI) 83352eabba5SLogan Gunthorpe ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_CLI; 83452eabba5SLogan Gunthorpe if (hdr & SWITCHTEC_EVENT_FATAL) 83552eabba5SLogan Gunthorpe ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_FATAL; 83652eabba5SLogan Gunthorpe 83752eabba5SLogan Gunthorpe return 0; 83852eabba5SLogan Gunthorpe } 83952eabba5SLogan Gunthorpe 84052eabba5SLogan Gunthorpe static int ioctl_event_ctl(struct switchtec_dev *stdev, 84152eabba5SLogan Gunthorpe struct switchtec_ioctl_event_ctl __user *uctl) 84252eabba5SLogan Gunthorpe { 84352eabba5SLogan Gunthorpe int ret; 84452eabba5SLogan Gunthorpe int nr_idxs; 845e4a7dca5SJoey Zhang unsigned int event_flags; 84652eabba5SLogan Gunthorpe struct switchtec_ioctl_event_ctl ctl; 84752eabba5SLogan Gunthorpe 84852eabba5SLogan Gunthorpe if (copy_from_user(&ctl, uctl, sizeof(ctl))) 84952eabba5SLogan Gunthorpe return -EFAULT; 85052eabba5SLogan Gunthorpe 85152eabba5SLogan Gunthorpe if (ctl.event_id >= SWITCHTEC_IOCTL_MAX_EVENTS) 85252eabba5SLogan Gunthorpe return -EINVAL; 85352eabba5SLogan Gunthorpe 85452eabba5SLogan Gunthorpe if (ctl.flags & SWITCHTEC_IOCTL_EVENT_FLAG_UNUSED) 85552eabba5SLogan Gunthorpe return -EINVAL; 85652eabba5SLogan Gunthorpe 85752eabba5SLogan Gunthorpe if (ctl.index == SWITCHTEC_IOCTL_EVENT_IDX_ALL) { 85852eabba5SLogan Gunthorpe if (event_regs[ctl.event_id].map_reg == global_ev_reg) 85952eabba5SLogan Gunthorpe nr_idxs = 1; 86052eabba5SLogan Gunthorpe else if (event_regs[ctl.event_id].map_reg == part_ev_reg) 86152eabba5SLogan Gunthorpe nr_idxs = stdev->partition_count; 86252eabba5SLogan Gunthorpe else if (event_regs[ctl.event_id].map_reg == pff_ev_reg) 86352eabba5SLogan Gunthorpe nr_idxs = stdev->pff_csr_count; 86452eabba5SLogan Gunthorpe else 86552eabba5SLogan Gunthorpe return -EINVAL; 86652eabba5SLogan Gunthorpe 867e4a7dca5SJoey Zhang event_flags = ctl.flags; 86852eabba5SLogan Gunthorpe for (ctl.index = 0; ctl.index < nr_idxs; ctl.index++) { 869e4a7dca5SJoey Zhang ctl.flags = event_flags; 87052eabba5SLogan Gunthorpe ret = event_ctl(stdev, &ctl); 87152eabba5SLogan Gunthorpe if (ret < 0) 87252eabba5SLogan Gunthorpe return ret; 87352eabba5SLogan Gunthorpe } 87452eabba5SLogan Gunthorpe } else { 87552eabba5SLogan Gunthorpe ret = event_ctl(stdev, &ctl); 87652eabba5SLogan Gunthorpe if (ret < 0) 87752eabba5SLogan Gunthorpe return ret; 87852eabba5SLogan Gunthorpe } 87952eabba5SLogan Gunthorpe 88052eabba5SLogan Gunthorpe if (copy_to_user(uctl, &ctl, sizeof(ctl))) 88152eabba5SLogan Gunthorpe return -EFAULT; 88252eabba5SLogan Gunthorpe 88352eabba5SLogan Gunthorpe return 0; 88452eabba5SLogan Gunthorpe } 88552eabba5SLogan Gunthorpe 88652eabba5SLogan Gunthorpe static int ioctl_pff_to_port(struct switchtec_dev *stdev, 88752eabba5SLogan Gunthorpe struct switchtec_ioctl_pff_port *up) 88852eabba5SLogan Gunthorpe { 88952eabba5SLogan Gunthorpe int i, part; 89052eabba5SLogan Gunthorpe u32 reg; 89152eabba5SLogan Gunthorpe struct part_cfg_regs *pcfg; 89252eabba5SLogan Gunthorpe struct switchtec_ioctl_pff_port p; 89352eabba5SLogan Gunthorpe 89452eabba5SLogan Gunthorpe if (copy_from_user(&p, up, sizeof(p))) 89552eabba5SLogan Gunthorpe return -EFAULT; 89652eabba5SLogan Gunthorpe 89752eabba5SLogan Gunthorpe p.port = -1; 89852eabba5SLogan Gunthorpe for (part = 0; part < stdev->partition_count; part++) { 89952eabba5SLogan Gunthorpe pcfg = &stdev->mmio_part_cfg_all[part]; 90052eabba5SLogan Gunthorpe p.partition = part; 90152eabba5SLogan Gunthorpe 90252eabba5SLogan Gunthorpe reg = ioread32(&pcfg->usp_pff_inst_id); 90352eabba5SLogan Gunthorpe if (reg == p.pff) { 90452eabba5SLogan Gunthorpe p.port = 0; 90552eabba5SLogan Gunthorpe break; 90652eabba5SLogan Gunthorpe } 90752eabba5SLogan Gunthorpe 90852eabba5SLogan Gunthorpe reg = ioread32(&pcfg->vep_pff_inst_id); 90952eabba5SLogan Gunthorpe if (reg == p.pff) { 91052eabba5SLogan Gunthorpe p.port = SWITCHTEC_IOCTL_PFF_VEP; 91152eabba5SLogan Gunthorpe break; 91252eabba5SLogan Gunthorpe } 91352eabba5SLogan Gunthorpe 91452eabba5SLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(pcfg->dsp_pff_inst_id); i++) { 91552eabba5SLogan Gunthorpe reg = ioread32(&pcfg->dsp_pff_inst_id[i]); 91652eabba5SLogan Gunthorpe if (reg != p.pff) 91752eabba5SLogan Gunthorpe continue; 91852eabba5SLogan Gunthorpe 91952eabba5SLogan Gunthorpe p.port = i + 1; 92052eabba5SLogan Gunthorpe break; 92152eabba5SLogan Gunthorpe } 92252eabba5SLogan Gunthorpe 92352eabba5SLogan Gunthorpe if (p.port != -1) 92452eabba5SLogan Gunthorpe break; 92552eabba5SLogan Gunthorpe } 92652eabba5SLogan Gunthorpe 92752eabba5SLogan Gunthorpe if (copy_to_user(up, &p, sizeof(p))) 92852eabba5SLogan Gunthorpe return -EFAULT; 92952eabba5SLogan Gunthorpe 93052eabba5SLogan Gunthorpe return 0; 93152eabba5SLogan Gunthorpe } 93252eabba5SLogan Gunthorpe 93352eabba5SLogan Gunthorpe static int ioctl_port_to_pff(struct switchtec_dev *stdev, 93452eabba5SLogan Gunthorpe struct switchtec_ioctl_pff_port *up) 93552eabba5SLogan Gunthorpe { 93652eabba5SLogan Gunthorpe struct switchtec_ioctl_pff_port p; 93752eabba5SLogan Gunthorpe struct part_cfg_regs *pcfg; 93852eabba5SLogan Gunthorpe 93952eabba5SLogan Gunthorpe if (copy_from_user(&p, up, sizeof(p))) 94052eabba5SLogan Gunthorpe return -EFAULT; 94152eabba5SLogan Gunthorpe 94252eabba5SLogan Gunthorpe if (p.partition == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX) 94352eabba5SLogan Gunthorpe pcfg = stdev->mmio_part_cfg; 94452eabba5SLogan Gunthorpe else if (p.partition < stdev->partition_count) 94552eabba5SLogan Gunthorpe pcfg = &stdev->mmio_part_cfg_all[p.partition]; 94652eabba5SLogan Gunthorpe else 94752eabba5SLogan Gunthorpe return -EINVAL; 94852eabba5SLogan Gunthorpe 94952eabba5SLogan Gunthorpe switch (p.port) { 95052eabba5SLogan Gunthorpe case 0: 95152eabba5SLogan Gunthorpe p.pff = ioread32(&pcfg->usp_pff_inst_id); 95252eabba5SLogan Gunthorpe break; 95352eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PFF_VEP: 95452eabba5SLogan Gunthorpe p.pff = ioread32(&pcfg->vep_pff_inst_id); 95552eabba5SLogan Gunthorpe break; 95652eabba5SLogan Gunthorpe default: 95752eabba5SLogan Gunthorpe if (p.port > ARRAY_SIZE(pcfg->dsp_pff_inst_id)) 95852eabba5SLogan Gunthorpe return -EINVAL; 95946feb6b4SGustavo A. R. Silva p.port = array_index_nospec(p.port, 96046feb6b4SGustavo A. R. Silva ARRAY_SIZE(pcfg->dsp_pff_inst_id) + 1); 96152eabba5SLogan Gunthorpe p.pff = ioread32(&pcfg->dsp_pff_inst_id[p.port - 1]); 96252eabba5SLogan Gunthorpe break; 96352eabba5SLogan Gunthorpe } 96452eabba5SLogan Gunthorpe 96552eabba5SLogan Gunthorpe if (copy_to_user(up, &p, sizeof(p))) 96652eabba5SLogan Gunthorpe return -EFAULT; 96752eabba5SLogan Gunthorpe 96852eabba5SLogan Gunthorpe return 0; 96952eabba5SLogan Gunthorpe } 97052eabba5SLogan Gunthorpe 97152eabba5SLogan Gunthorpe static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd, 97252eabba5SLogan Gunthorpe unsigned long arg) 97352eabba5SLogan Gunthorpe { 97452eabba5SLogan Gunthorpe struct switchtec_user *stuser = filp->private_data; 97552eabba5SLogan Gunthorpe struct switchtec_dev *stdev = stuser->stdev; 97652eabba5SLogan Gunthorpe int rc; 97752eabba5SLogan Gunthorpe void __user *argp = (void __user *)arg; 97852eabba5SLogan Gunthorpe 97952eabba5SLogan Gunthorpe rc = lock_mutex_and_test_alive(stdev); 98052eabba5SLogan Gunthorpe if (rc) 98152eabba5SLogan Gunthorpe return rc; 98252eabba5SLogan Gunthorpe 98352eabba5SLogan Gunthorpe switch (cmd) { 98452eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_FLASH_INFO: 98552eabba5SLogan Gunthorpe rc = ioctl_flash_info(stdev, argp); 98652eabba5SLogan Gunthorpe break; 98752eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_FLASH_PART_INFO: 98852eabba5SLogan Gunthorpe rc = ioctl_flash_part_info(stdev, argp); 98952eabba5SLogan Gunthorpe break; 990*ba8a3982SWesley Sheng case SWITCHTEC_IOCTL_EVENT_SUMMARY_LEGACY: 991*ba8a3982SWesley Sheng rc = ioctl_event_summary(stdev, stuser, argp, 992*ba8a3982SWesley Sheng sizeof(struct switchtec_ioctl_event_summary_legacy)); 99352eabba5SLogan Gunthorpe break; 99452eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_EVENT_CTL: 99552eabba5SLogan Gunthorpe rc = ioctl_event_ctl(stdev, argp); 99652eabba5SLogan Gunthorpe break; 99752eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PFF_TO_PORT: 99852eabba5SLogan Gunthorpe rc = ioctl_pff_to_port(stdev, argp); 99952eabba5SLogan Gunthorpe break; 100052eabba5SLogan Gunthorpe case SWITCHTEC_IOCTL_PORT_TO_PFF: 100152eabba5SLogan Gunthorpe rc = ioctl_port_to_pff(stdev, argp); 100252eabba5SLogan Gunthorpe break; 1003*ba8a3982SWesley Sheng case SWITCHTEC_IOCTL_EVENT_SUMMARY: 1004*ba8a3982SWesley Sheng rc = ioctl_event_summary(stdev, stuser, argp, 1005*ba8a3982SWesley Sheng sizeof(struct switchtec_ioctl_event_summary)); 1006*ba8a3982SWesley Sheng break; 100752eabba5SLogan Gunthorpe default: 100852eabba5SLogan Gunthorpe rc = -ENOTTY; 100952eabba5SLogan Gunthorpe break; 101052eabba5SLogan Gunthorpe } 101152eabba5SLogan Gunthorpe 101252eabba5SLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 101352eabba5SLogan Gunthorpe return rc; 101452eabba5SLogan Gunthorpe } 101552eabba5SLogan Gunthorpe 1016080b47deSLogan Gunthorpe static const struct file_operations switchtec_fops = { 1017080b47deSLogan Gunthorpe .owner = THIS_MODULE, 1018080b47deSLogan Gunthorpe .open = switchtec_dev_open, 1019080b47deSLogan Gunthorpe .release = switchtec_dev_release, 1020080b47deSLogan Gunthorpe .write = switchtec_dev_write, 1021080b47deSLogan Gunthorpe .read = switchtec_dev_read, 1022080b47deSLogan Gunthorpe .poll = switchtec_dev_poll, 102352eabba5SLogan Gunthorpe .unlocked_ioctl = switchtec_dev_ioctl, 102452eabba5SLogan Gunthorpe .compat_ioctl = switchtec_dev_ioctl, 1025080b47deSLogan Gunthorpe }; 1026080b47deSLogan Gunthorpe 102748c302dcSLogan Gunthorpe static void link_event_work(struct work_struct *work) 102848c302dcSLogan Gunthorpe { 102948c302dcSLogan Gunthorpe struct switchtec_dev *stdev; 103048c302dcSLogan Gunthorpe 103148c302dcSLogan Gunthorpe stdev = container_of(work, struct switchtec_dev, link_event_work); 103248c302dcSLogan Gunthorpe 103348c302dcSLogan Gunthorpe if (stdev->link_notifier) 103448c302dcSLogan Gunthorpe stdev->link_notifier(stdev); 103548c302dcSLogan Gunthorpe } 103648c302dcSLogan Gunthorpe 103748c302dcSLogan Gunthorpe static void check_link_state_events(struct switchtec_dev *stdev) 103848c302dcSLogan Gunthorpe { 103948c302dcSLogan Gunthorpe int idx; 104048c302dcSLogan Gunthorpe u32 reg; 104148c302dcSLogan Gunthorpe int count; 104248c302dcSLogan Gunthorpe int occurred = 0; 104348c302dcSLogan Gunthorpe 104448c302dcSLogan Gunthorpe for (idx = 0; idx < stdev->pff_csr_count; idx++) { 104548c302dcSLogan Gunthorpe reg = ioread32(&stdev->mmio_pff_csr[idx].link_state_hdr); 104648c302dcSLogan Gunthorpe dev_dbg(&stdev->dev, "link_state: %d->%08x\n", idx, reg); 104748c302dcSLogan Gunthorpe count = (reg >> 5) & 0xFF; 104848c302dcSLogan Gunthorpe 104948c302dcSLogan Gunthorpe if (count != stdev->link_event_count[idx]) { 105048c302dcSLogan Gunthorpe occurred = 1; 105148c302dcSLogan Gunthorpe stdev->link_event_count[idx] = count; 105248c302dcSLogan Gunthorpe } 105348c302dcSLogan Gunthorpe } 105448c302dcSLogan Gunthorpe 105548c302dcSLogan Gunthorpe if (occurred) 105648c302dcSLogan Gunthorpe schedule_work(&stdev->link_event_work); 105748c302dcSLogan Gunthorpe } 105848c302dcSLogan Gunthorpe 105948c302dcSLogan Gunthorpe static void enable_link_state_events(struct switchtec_dev *stdev) 106048c302dcSLogan Gunthorpe { 106148c302dcSLogan Gunthorpe int idx; 106248c302dcSLogan Gunthorpe 106348c302dcSLogan Gunthorpe for (idx = 0; idx < stdev->pff_csr_count; idx++) { 106448c302dcSLogan Gunthorpe iowrite32(SWITCHTEC_EVENT_CLEAR | 106548c302dcSLogan Gunthorpe SWITCHTEC_EVENT_EN_IRQ, 106648c302dcSLogan Gunthorpe &stdev->mmio_pff_csr[idx].link_state_hdr); 106748c302dcSLogan Gunthorpe } 106848c302dcSLogan Gunthorpe } 106948c302dcSLogan Gunthorpe 1070f7eb7b8aSWesley Sheng static void enable_dma_mrpc(struct switchtec_dev *stdev) 1071f7eb7b8aSWesley Sheng { 1072f7eb7b8aSWesley Sheng writeq(stdev->dma_mrpc_dma_addr, &stdev->mmio_mrpc->dma_addr); 1073f7eb7b8aSWesley Sheng flush_wc_buf(stdev); 1074f7eb7b8aSWesley Sheng iowrite32(SWITCHTEC_DMA_MRPC_EN, &stdev->mmio_mrpc->dma_en); 1075f7eb7b8aSWesley Sheng } 1076f7eb7b8aSWesley Sheng 1077080b47deSLogan Gunthorpe static void stdev_release(struct device *dev) 1078080b47deSLogan Gunthorpe { 1079080b47deSLogan Gunthorpe struct switchtec_dev *stdev = to_stdev(dev); 1080080b47deSLogan Gunthorpe 1081f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) { 1082f7eb7b8aSWesley Sheng iowrite32(0, &stdev->mmio_mrpc->dma_en); 1083f7eb7b8aSWesley Sheng flush_wc_buf(stdev); 1084f7eb7b8aSWesley Sheng writeq(0, &stdev->mmio_mrpc->dma_addr); 1085f7eb7b8aSWesley Sheng dma_free_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc), 1086f7eb7b8aSWesley Sheng stdev->dma_mrpc, stdev->dma_mrpc_dma_addr); 1087f7eb7b8aSWesley Sheng } 1088080b47deSLogan Gunthorpe kfree(stdev); 1089080b47deSLogan Gunthorpe } 1090080b47deSLogan Gunthorpe 1091080b47deSLogan Gunthorpe static void stdev_kill(struct switchtec_dev *stdev) 1092080b47deSLogan Gunthorpe { 1093080b47deSLogan Gunthorpe struct switchtec_user *stuser, *tmpuser; 1094080b47deSLogan Gunthorpe 1095080b47deSLogan Gunthorpe pci_clear_master(stdev->pdev); 1096080b47deSLogan Gunthorpe 1097080b47deSLogan Gunthorpe cancel_delayed_work_sync(&stdev->mrpc_timeout); 1098080b47deSLogan Gunthorpe 1099080b47deSLogan Gunthorpe /* Mark the hardware as unavailable and complete all completions */ 1100080b47deSLogan Gunthorpe mutex_lock(&stdev->mrpc_mutex); 1101080b47deSLogan Gunthorpe stdev->alive = false; 1102080b47deSLogan Gunthorpe 1103080b47deSLogan Gunthorpe /* Wake up and kill any users waiting on an MRPC request */ 1104080b47deSLogan Gunthorpe list_for_each_entry_safe(stuser, tmpuser, &stdev->mrpc_queue, list) { 1105080b47deSLogan Gunthorpe complete_all(&stuser->comp); 1106080b47deSLogan Gunthorpe list_del_init(&stuser->list); 1107080b47deSLogan Gunthorpe stuser_put(stuser); 1108080b47deSLogan Gunthorpe } 1109080b47deSLogan Gunthorpe 1110080b47deSLogan Gunthorpe mutex_unlock(&stdev->mrpc_mutex); 1111080b47deSLogan Gunthorpe 1112080b47deSLogan Gunthorpe /* Wake up any users waiting on event_wq */ 1113080b47deSLogan Gunthorpe wake_up_interruptible(&stdev->event_wq); 1114080b47deSLogan Gunthorpe } 1115080b47deSLogan Gunthorpe 1116080b47deSLogan Gunthorpe static struct switchtec_dev *stdev_create(struct pci_dev *pdev) 1117080b47deSLogan Gunthorpe { 1118080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 1119080b47deSLogan Gunthorpe int minor; 1120080b47deSLogan Gunthorpe struct device *dev; 1121080b47deSLogan Gunthorpe struct cdev *cdev; 1122080b47deSLogan Gunthorpe int rc; 1123080b47deSLogan Gunthorpe 1124080b47deSLogan Gunthorpe stdev = kzalloc_node(sizeof(*stdev), GFP_KERNEL, 1125080b47deSLogan Gunthorpe dev_to_node(&pdev->dev)); 1126080b47deSLogan Gunthorpe if (!stdev) 1127080b47deSLogan Gunthorpe return ERR_PTR(-ENOMEM); 1128080b47deSLogan Gunthorpe 1129080b47deSLogan Gunthorpe stdev->alive = true; 1130080b47deSLogan Gunthorpe stdev->pdev = pdev; 1131080b47deSLogan Gunthorpe INIT_LIST_HEAD(&stdev->mrpc_queue); 1132080b47deSLogan Gunthorpe mutex_init(&stdev->mrpc_mutex); 1133080b47deSLogan Gunthorpe stdev->mrpc_busy = 0; 1134080b47deSLogan Gunthorpe INIT_WORK(&stdev->mrpc_work, mrpc_event_work); 1135080b47deSLogan Gunthorpe INIT_DELAYED_WORK(&stdev->mrpc_timeout, mrpc_timeout_work); 113648c302dcSLogan Gunthorpe INIT_WORK(&stdev->link_event_work, link_event_work); 1137080b47deSLogan Gunthorpe init_waitqueue_head(&stdev->event_wq); 1138080b47deSLogan Gunthorpe atomic_set(&stdev->event_cnt, 0); 1139080b47deSLogan Gunthorpe 1140080b47deSLogan Gunthorpe dev = &stdev->dev; 1141080b47deSLogan Gunthorpe device_initialize(dev); 1142080b47deSLogan Gunthorpe dev->class = switchtec_class; 1143080b47deSLogan Gunthorpe dev->parent = &pdev->dev; 11445d8e1881SLogan Gunthorpe dev->groups = switchtec_device_groups; 1145080b47deSLogan Gunthorpe dev->release = stdev_release; 1146080b47deSLogan Gunthorpe 1147080b47deSLogan Gunthorpe minor = ida_simple_get(&switchtec_minor_ida, 0, 0, 1148080b47deSLogan Gunthorpe GFP_KERNEL); 1149080b47deSLogan Gunthorpe if (minor < 0) { 1150080b47deSLogan Gunthorpe rc = minor; 1151080b47deSLogan Gunthorpe goto err_put; 1152080b47deSLogan Gunthorpe } 1153080b47deSLogan Gunthorpe 1154080b47deSLogan Gunthorpe dev->devt = MKDEV(MAJOR(switchtec_devt), minor); 1155080b47deSLogan Gunthorpe dev_set_name(dev, "switchtec%d", minor); 1156080b47deSLogan Gunthorpe 1157080b47deSLogan Gunthorpe cdev = &stdev->cdev; 1158080b47deSLogan Gunthorpe cdev_init(cdev, &switchtec_fops); 1159080b47deSLogan Gunthorpe cdev->owner = THIS_MODULE; 1160080b47deSLogan Gunthorpe 1161080b47deSLogan Gunthorpe return stdev; 1162080b47deSLogan Gunthorpe 1163080b47deSLogan Gunthorpe err_put: 1164080b47deSLogan Gunthorpe put_device(&stdev->dev); 1165080b47deSLogan Gunthorpe return ERR_PTR(rc); 1166080b47deSLogan Gunthorpe } 1167080b47deSLogan Gunthorpe 116852eabba5SLogan Gunthorpe static int mask_event(struct switchtec_dev *stdev, int eid, int idx) 116952eabba5SLogan Gunthorpe { 117052eabba5SLogan Gunthorpe size_t off = event_regs[eid].offset; 117152eabba5SLogan Gunthorpe u32 __iomem *hdr_reg; 117252eabba5SLogan Gunthorpe u32 hdr; 117352eabba5SLogan Gunthorpe 117452eabba5SLogan Gunthorpe hdr_reg = event_regs[eid].map_reg(stdev, off, idx); 117552eabba5SLogan Gunthorpe hdr = ioread32(hdr_reg); 117652eabba5SLogan Gunthorpe 117752eabba5SLogan Gunthorpe if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ)) 117852eabba5SLogan Gunthorpe return 0; 117952eabba5SLogan Gunthorpe 118048c302dcSLogan Gunthorpe if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE) 118148c302dcSLogan Gunthorpe return 0; 118248c302dcSLogan Gunthorpe 118352eabba5SLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %d %d %x\n", __func__, eid, idx, hdr); 118452eabba5SLogan Gunthorpe hdr &= ~(SWITCHTEC_EVENT_EN_IRQ | SWITCHTEC_EVENT_OCCURRED); 118552eabba5SLogan Gunthorpe iowrite32(hdr, hdr_reg); 118652eabba5SLogan Gunthorpe 118752eabba5SLogan Gunthorpe return 1; 118852eabba5SLogan Gunthorpe } 118952eabba5SLogan Gunthorpe 119052eabba5SLogan Gunthorpe static int mask_all_events(struct switchtec_dev *stdev, int eid) 119152eabba5SLogan Gunthorpe { 119252eabba5SLogan Gunthorpe int idx; 119352eabba5SLogan Gunthorpe int count = 0; 119452eabba5SLogan Gunthorpe 119552eabba5SLogan Gunthorpe if (event_regs[eid].map_reg == part_ev_reg) { 119652eabba5SLogan Gunthorpe for (idx = 0; idx < stdev->partition_count; idx++) 119752eabba5SLogan Gunthorpe count += mask_event(stdev, eid, idx); 119852eabba5SLogan Gunthorpe } else if (event_regs[eid].map_reg == pff_ev_reg) { 119952eabba5SLogan Gunthorpe for (idx = 0; idx < stdev->pff_csr_count; idx++) { 120052eabba5SLogan Gunthorpe if (!stdev->pff_local[idx]) 120152eabba5SLogan Gunthorpe continue; 120248c302dcSLogan Gunthorpe 120352eabba5SLogan Gunthorpe count += mask_event(stdev, eid, idx); 120452eabba5SLogan Gunthorpe } 120552eabba5SLogan Gunthorpe } else { 120652eabba5SLogan Gunthorpe count += mask_event(stdev, eid, 0); 120752eabba5SLogan Gunthorpe } 120852eabba5SLogan Gunthorpe 120952eabba5SLogan Gunthorpe return count; 121052eabba5SLogan Gunthorpe } 121152eabba5SLogan Gunthorpe 1212080b47deSLogan Gunthorpe static irqreturn_t switchtec_event_isr(int irq, void *dev) 1213080b47deSLogan Gunthorpe { 1214080b47deSLogan Gunthorpe struct switchtec_dev *stdev = dev; 1215080b47deSLogan Gunthorpe u32 reg; 1216080b47deSLogan Gunthorpe irqreturn_t ret = IRQ_NONE; 121752eabba5SLogan Gunthorpe int eid, event_count = 0; 1218080b47deSLogan Gunthorpe 1219080b47deSLogan Gunthorpe reg = ioread32(&stdev->mmio_part_cfg->mrpc_comp_hdr); 1220080b47deSLogan Gunthorpe if (reg & SWITCHTEC_EVENT_OCCURRED) { 1221080b47deSLogan Gunthorpe dev_dbg(&stdev->dev, "%s: mrpc comp\n", __func__); 1222080b47deSLogan Gunthorpe ret = IRQ_HANDLED; 1223080b47deSLogan Gunthorpe schedule_work(&stdev->mrpc_work); 1224080b47deSLogan Gunthorpe iowrite32(reg, &stdev->mmio_part_cfg->mrpc_comp_hdr); 1225080b47deSLogan Gunthorpe } 1226080b47deSLogan Gunthorpe 122748c302dcSLogan Gunthorpe check_link_state_events(stdev); 122848c302dcSLogan Gunthorpe 122952eabba5SLogan Gunthorpe for (eid = 0; eid < SWITCHTEC_IOCTL_MAX_EVENTS; eid++) 123052eabba5SLogan Gunthorpe event_count += mask_all_events(stdev, eid); 123152eabba5SLogan Gunthorpe 123252eabba5SLogan Gunthorpe if (event_count) { 123352eabba5SLogan Gunthorpe atomic_inc(&stdev->event_cnt); 123452eabba5SLogan Gunthorpe wake_up_interruptible(&stdev->event_wq); 123552eabba5SLogan Gunthorpe dev_dbg(&stdev->dev, "%s: %d events\n", __func__, 123652eabba5SLogan Gunthorpe event_count); 123752eabba5SLogan Gunthorpe return IRQ_HANDLED; 123852eabba5SLogan Gunthorpe } 123952eabba5SLogan Gunthorpe 1240080b47deSLogan Gunthorpe return ret; 1241080b47deSLogan Gunthorpe } 1242080b47deSLogan Gunthorpe 1243f7eb7b8aSWesley Sheng 1244f7eb7b8aSWesley Sheng static irqreturn_t switchtec_dma_mrpc_isr(int irq, void *dev) 1245f7eb7b8aSWesley Sheng { 1246f7eb7b8aSWesley Sheng struct switchtec_dev *stdev = dev; 1247f7eb7b8aSWesley Sheng irqreturn_t ret = IRQ_NONE; 1248f7eb7b8aSWesley Sheng 1249f7eb7b8aSWesley Sheng iowrite32(SWITCHTEC_EVENT_CLEAR | 1250f7eb7b8aSWesley Sheng SWITCHTEC_EVENT_EN_IRQ, 1251f7eb7b8aSWesley Sheng &stdev->mmio_part_cfg->mrpc_comp_hdr); 1252f7eb7b8aSWesley Sheng schedule_work(&stdev->mrpc_work); 1253f7eb7b8aSWesley Sheng 1254f7eb7b8aSWesley Sheng ret = IRQ_HANDLED; 1255f7eb7b8aSWesley Sheng return ret; 1256f7eb7b8aSWesley Sheng } 1257f7eb7b8aSWesley Sheng 1258080b47deSLogan Gunthorpe static int switchtec_init_isr(struct switchtec_dev *stdev) 1259080b47deSLogan Gunthorpe { 1260080b47deSLogan Gunthorpe int nvecs; 1261080b47deSLogan Gunthorpe int event_irq; 1262f7eb7b8aSWesley Sheng int dma_mrpc_irq; 1263f7eb7b8aSWesley Sheng int rc; 1264080b47deSLogan Gunthorpe 1265080b47deSLogan Gunthorpe nvecs = pci_alloc_irq_vectors(stdev->pdev, 1, 4, 1266080b47deSLogan Gunthorpe PCI_IRQ_MSIX | PCI_IRQ_MSI); 1267080b47deSLogan Gunthorpe if (nvecs < 0) 1268080b47deSLogan Gunthorpe return nvecs; 1269080b47deSLogan Gunthorpe 1270080b47deSLogan Gunthorpe event_irq = ioread32(&stdev->mmio_part_cfg->vep_vector_number); 1271080b47deSLogan Gunthorpe if (event_irq < 0 || event_irq >= nvecs) 1272080b47deSLogan Gunthorpe return -EFAULT; 1273080b47deSLogan Gunthorpe 1274080b47deSLogan Gunthorpe event_irq = pci_irq_vector(stdev->pdev, event_irq); 1275080b47deSLogan Gunthorpe if (event_irq < 0) 1276080b47deSLogan Gunthorpe return event_irq; 1277080b47deSLogan Gunthorpe 1278f7eb7b8aSWesley Sheng rc = devm_request_irq(&stdev->pdev->dev, event_irq, 1279080b47deSLogan Gunthorpe switchtec_event_isr, 0, 1280080b47deSLogan Gunthorpe KBUILD_MODNAME, stdev); 1281f7eb7b8aSWesley Sheng 1282f7eb7b8aSWesley Sheng if (rc) 1283f7eb7b8aSWesley Sheng return rc; 1284f7eb7b8aSWesley Sheng 1285f7eb7b8aSWesley Sheng if (!stdev->dma_mrpc) 1286f7eb7b8aSWesley Sheng return rc; 1287f7eb7b8aSWesley Sheng 1288f7eb7b8aSWesley Sheng dma_mrpc_irq = ioread32(&stdev->mmio_mrpc->dma_vector); 1289f7eb7b8aSWesley Sheng if (dma_mrpc_irq < 0 || dma_mrpc_irq >= nvecs) 1290f7eb7b8aSWesley Sheng return -EFAULT; 1291f7eb7b8aSWesley Sheng 1292f7eb7b8aSWesley Sheng dma_mrpc_irq = pci_irq_vector(stdev->pdev, dma_mrpc_irq); 1293f7eb7b8aSWesley Sheng if (dma_mrpc_irq < 0) 1294f7eb7b8aSWesley Sheng return dma_mrpc_irq; 1295f7eb7b8aSWesley Sheng 1296f7eb7b8aSWesley Sheng rc = devm_request_irq(&stdev->pdev->dev, dma_mrpc_irq, 1297f7eb7b8aSWesley Sheng switchtec_dma_mrpc_isr, 0, 1298f7eb7b8aSWesley Sheng KBUILD_MODNAME, stdev); 1299f7eb7b8aSWesley Sheng 1300f7eb7b8aSWesley Sheng return rc; 1301080b47deSLogan Gunthorpe } 1302080b47deSLogan Gunthorpe 1303080b47deSLogan Gunthorpe static void init_pff(struct switchtec_dev *stdev) 1304080b47deSLogan Gunthorpe { 1305080b47deSLogan Gunthorpe int i; 1306080b47deSLogan Gunthorpe u32 reg; 1307080b47deSLogan Gunthorpe struct part_cfg_regs *pcfg = stdev->mmio_part_cfg; 1308080b47deSLogan Gunthorpe 1309080b47deSLogan Gunthorpe for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) { 1310080b47deSLogan Gunthorpe reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id); 1311cfdfc14eSDoug Meyer if (reg != PCI_VENDOR_ID_MICROSEMI) 1312080b47deSLogan Gunthorpe break; 1313080b47deSLogan Gunthorpe } 1314080b47deSLogan Gunthorpe 1315080b47deSLogan Gunthorpe stdev->pff_csr_count = i; 1316080b47deSLogan Gunthorpe 1317080b47deSLogan Gunthorpe reg = ioread32(&pcfg->usp_pff_inst_id); 1318080b47deSLogan Gunthorpe if (reg < SWITCHTEC_MAX_PFF_CSR) 1319080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 1320080b47deSLogan Gunthorpe 1321080b47deSLogan Gunthorpe reg = ioread32(&pcfg->vep_pff_inst_id); 1322080b47deSLogan Gunthorpe if (reg < SWITCHTEC_MAX_PFF_CSR) 1323080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 1324080b47deSLogan Gunthorpe 1325080b47deSLogan Gunthorpe for (i = 0; i < ARRAY_SIZE(pcfg->dsp_pff_inst_id); i++) { 1326080b47deSLogan Gunthorpe reg = ioread32(&pcfg->dsp_pff_inst_id[i]); 1327080b47deSLogan Gunthorpe if (reg < SWITCHTEC_MAX_PFF_CSR) 1328080b47deSLogan Gunthorpe stdev->pff_local[reg] = 1; 1329080b47deSLogan Gunthorpe } 1330080b47deSLogan Gunthorpe } 1331080b47deSLogan Gunthorpe 1332080b47deSLogan Gunthorpe static int switchtec_init_pci(struct switchtec_dev *stdev, 1333080b47deSLogan Gunthorpe struct pci_dev *pdev) 1334080b47deSLogan Gunthorpe { 1335080b47deSLogan Gunthorpe int rc; 133652d8db8eSKelvin Cao void __iomem *map; 133752d8db8eSKelvin Cao unsigned long res_start, res_len; 1338080b47deSLogan Gunthorpe 1339080b47deSLogan Gunthorpe rc = pcim_enable_device(pdev); 1340080b47deSLogan Gunthorpe if (rc) 1341080b47deSLogan Gunthorpe return rc; 1342080b47deSLogan Gunthorpe 1343aff614c6SBoris Glimcher rc = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); 1344aff614c6SBoris Glimcher if (rc) 1345aff614c6SBoris Glimcher return rc; 1346aff614c6SBoris Glimcher 1347080b47deSLogan Gunthorpe pci_set_master(pdev); 1348080b47deSLogan Gunthorpe 134952d8db8eSKelvin Cao res_start = pci_resource_start(pdev, 0); 135052d8db8eSKelvin Cao res_len = pci_resource_len(pdev, 0); 135152d8db8eSKelvin Cao 135252d8db8eSKelvin Cao if (!devm_request_mem_region(&pdev->dev, res_start, 135352d8db8eSKelvin Cao res_len, KBUILD_MODNAME)) 135452d8db8eSKelvin Cao return -EBUSY; 135552d8db8eSKelvin Cao 135652d8db8eSKelvin Cao stdev->mmio_mrpc = devm_ioremap_wc(&pdev->dev, res_start, 135752d8db8eSKelvin Cao SWITCHTEC_GAS_TOP_CFG_OFFSET); 135852d8db8eSKelvin Cao if (!stdev->mmio_mrpc) 135952d8db8eSKelvin Cao return -ENOMEM; 136052d8db8eSKelvin Cao 136152d8db8eSKelvin Cao map = devm_ioremap(&pdev->dev, 136252d8db8eSKelvin Cao res_start + SWITCHTEC_GAS_TOP_CFG_OFFSET, 136352d8db8eSKelvin Cao res_len - SWITCHTEC_GAS_TOP_CFG_OFFSET); 136452d8db8eSKelvin Cao if (!map) 136552d8db8eSKelvin Cao return -ENOMEM; 136652d8db8eSKelvin Cao 136752d8db8eSKelvin Cao stdev->mmio = map - SWITCHTEC_GAS_TOP_CFG_OFFSET; 1368080b47deSLogan Gunthorpe stdev->mmio_sw_event = stdev->mmio + SWITCHTEC_GAS_SW_EVENT_OFFSET; 1369080b47deSLogan Gunthorpe stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET; 1370080b47deSLogan Gunthorpe stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET; 1371080b47deSLogan Gunthorpe stdev->mmio_ntb = stdev->mmio + SWITCHTEC_GAS_NTB_OFFSET; 13729871e9bbSLogan Gunthorpe stdev->partition = ioread8(&stdev->mmio_sys_info->partition_id); 1373080b47deSLogan Gunthorpe stdev->partition_count = ioread8(&stdev->mmio_ntb->partition_count); 1374080b47deSLogan Gunthorpe stdev->mmio_part_cfg_all = stdev->mmio + SWITCHTEC_GAS_PART_CFG_OFFSET; 1375080b47deSLogan Gunthorpe stdev->mmio_part_cfg = &stdev->mmio_part_cfg_all[stdev->partition]; 1376080b47deSLogan Gunthorpe stdev->mmio_pff_csr = stdev->mmio + SWITCHTEC_GAS_PFF_CSR_OFFSET; 1377080b47deSLogan Gunthorpe 13789871e9bbSLogan Gunthorpe if (stdev->partition_count < 1) 13799871e9bbSLogan Gunthorpe stdev->partition_count = 1; 13809871e9bbSLogan Gunthorpe 1381080b47deSLogan Gunthorpe init_pff(stdev); 1382080b47deSLogan Gunthorpe 1383080b47deSLogan Gunthorpe pci_set_drvdata(pdev, stdev); 1384080b47deSLogan Gunthorpe 1385f7eb7b8aSWesley Sheng if (!use_dma_mrpc) 1386f7eb7b8aSWesley Sheng return 0; 1387f7eb7b8aSWesley Sheng 1388f7eb7b8aSWesley Sheng if (ioread32(&stdev->mmio_mrpc->dma_ver) == 0) 1389f7eb7b8aSWesley Sheng return 0; 1390f7eb7b8aSWesley Sheng 1391750afb08SLuis Chamberlain stdev->dma_mrpc = dma_alloc_coherent(&stdev->pdev->dev, 1392f7eb7b8aSWesley Sheng sizeof(*stdev->dma_mrpc), 1393f7eb7b8aSWesley Sheng &stdev->dma_mrpc_dma_addr, 1394f7eb7b8aSWesley Sheng GFP_KERNEL); 1395f7eb7b8aSWesley Sheng if (stdev->dma_mrpc == NULL) 1396f7eb7b8aSWesley Sheng return -ENOMEM; 1397f7eb7b8aSWesley Sheng 1398080b47deSLogan Gunthorpe return 0; 1399080b47deSLogan Gunthorpe } 1400080b47deSLogan Gunthorpe 1401080b47deSLogan Gunthorpe static int switchtec_pci_probe(struct pci_dev *pdev, 1402080b47deSLogan Gunthorpe const struct pci_device_id *id) 1403080b47deSLogan Gunthorpe { 1404080b47deSLogan Gunthorpe struct switchtec_dev *stdev; 1405080b47deSLogan Gunthorpe int rc; 1406080b47deSLogan Gunthorpe 1407cfdfc14eSDoug Meyer if (pdev->class == (PCI_CLASS_BRIDGE_OTHER << 8)) 140833dea5aaSLogan Gunthorpe request_module_nowait("ntb_hw_switchtec"); 140933dea5aaSLogan Gunthorpe 1410080b47deSLogan Gunthorpe stdev = stdev_create(pdev); 1411080b47deSLogan Gunthorpe if (IS_ERR(stdev)) 1412080b47deSLogan Gunthorpe return PTR_ERR(stdev); 1413080b47deSLogan Gunthorpe 1414080b47deSLogan Gunthorpe rc = switchtec_init_pci(stdev, pdev); 1415080b47deSLogan Gunthorpe if (rc) 1416080b47deSLogan Gunthorpe goto err_put; 1417080b47deSLogan Gunthorpe 1418080b47deSLogan Gunthorpe rc = switchtec_init_isr(stdev); 1419080b47deSLogan Gunthorpe if (rc) { 1420080b47deSLogan Gunthorpe dev_err(&stdev->dev, "failed to init isr.\n"); 1421080b47deSLogan Gunthorpe goto err_put; 1422080b47deSLogan Gunthorpe } 1423080b47deSLogan Gunthorpe 1424080b47deSLogan Gunthorpe iowrite32(SWITCHTEC_EVENT_CLEAR | 1425080b47deSLogan Gunthorpe SWITCHTEC_EVENT_EN_IRQ, 1426080b47deSLogan Gunthorpe &stdev->mmio_part_cfg->mrpc_comp_hdr); 142748c302dcSLogan Gunthorpe enable_link_state_events(stdev); 1428080b47deSLogan Gunthorpe 1429f7eb7b8aSWesley Sheng if (stdev->dma_mrpc) 1430f7eb7b8aSWesley Sheng enable_dma_mrpc(stdev); 1431f7eb7b8aSWesley Sheng 1432e40cf640SLogan Gunthorpe rc = cdev_device_add(&stdev->cdev, &stdev->dev); 1433080b47deSLogan Gunthorpe if (rc) 1434080b47deSLogan Gunthorpe goto err_devadd; 1435080b47deSLogan Gunthorpe 1436080b47deSLogan Gunthorpe dev_info(&stdev->dev, "Management device registered.\n"); 1437080b47deSLogan Gunthorpe 1438080b47deSLogan Gunthorpe return 0; 1439080b47deSLogan Gunthorpe 1440080b47deSLogan Gunthorpe err_devadd: 1441080b47deSLogan Gunthorpe stdev_kill(stdev); 1442080b47deSLogan Gunthorpe err_put: 1443080b47deSLogan Gunthorpe ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); 1444080b47deSLogan Gunthorpe put_device(&stdev->dev); 1445080b47deSLogan Gunthorpe return rc; 1446080b47deSLogan Gunthorpe } 1447080b47deSLogan Gunthorpe 1448080b47deSLogan Gunthorpe static void switchtec_pci_remove(struct pci_dev *pdev) 1449080b47deSLogan Gunthorpe { 1450080b47deSLogan Gunthorpe struct switchtec_dev *stdev = pci_get_drvdata(pdev); 1451080b47deSLogan Gunthorpe 1452080b47deSLogan Gunthorpe pci_set_drvdata(pdev, NULL); 1453080b47deSLogan Gunthorpe 1454e40cf640SLogan Gunthorpe cdev_device_del(&stdev->cdev, &stdev->dev); 1455080b47deSLogan Gunthorpe ida_simple_remove(&switchtec_minor_ida, MINOR(stdev->dev.devt)); 1456080b47deSLogan Gunthorpe dev_info(&stdev->dev, "unregistered.\n"); 1457080b47deSLogan Gunthorpe stdev_kill(stdev); 1458080b47deSLogan Gunthorpe put_device(&stdev->dev); 1459080b47deSLogan Gunthorpe } 1460080b47deSLogan Gunthorpe 1461080b47deSLogan Gunthorpe #define SWITCHTEC_PCI_DEVICE(device_id) \ 1462080b47deSLogan Gunthorpe { \ 1463cfdfc14eSDoug Meyer .vendor = PCI_VENDOR_ID_MICROSEMI, \ 1464080b47deSLogan Gunthorpe .device = device_id, \ 1465080b47deSLogan Gunthorpe .subvendor = PCI_ANY_ID, \ 1466080b47deSLogan Gunthorpe .subdevice = PCI_ANY_ID, \ 1467cfdfc14eSDoug Meyer .class = (PCI_CLASS_MEMORY_OTHER << 8), \ 1468080b47deSLogan Gunthorpe .class_mask = 0xFFFFFFFF, \ 1469080b47deSLogan Gunthorpe }, \ 1470080b47deSLogan Gunthorpe { \ 1471cfdfc14eSDoug Meyer .vendor = PCI_VENDOR_ID_MICROSEMI, \ 1472080b47deSLogan Gunthorpe .device = device_id, \ 1473080b47deSLogan Gunthorpe .subvendor = PCI_ANY_ID, \ 1474080b47deSLogan Gunthorpe .subdevice = PCI_ANY_ID, \ 1475cfdfc14eSDoug Meyer .class = (PCI_CLASS_BRIDGE_OTHER << 8), \ 1476080b47deSLogan Gunthorpe .class_mask = 0xFFFFFFFF, \ 1477080b47deSLogan Gunthorpe } 1478080b47deSLogan Gunthorpe 1479080b47deSLogan Gunthorpe static const struct pci_device_id switchtec_pci_tbl[] = { 1480080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8531), //PFX 24xG3 1481080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8532), //PFX 32xG3 1482080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8533), //PFX 48xG3 1483080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8534), //PFX 64xG3 1484080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8535), //PFX 80xG3 1485080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8536), //PFX 96xG3 1486bb6b42b4SKelvin Cao SWITCHTEC_PCI_DEVICE(0x8541), //PSX 24xG3 1487bb6b42b4SKelvin Cao SWITCHTEC_PCI_DEVICE(0x8542), //PSX 32xG3 1488080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8543), //PSX 48xG3 1489080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8544), //PSX 64xG3 1490080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8545), //PSX 80xG3 1491080b47deSLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8546), //PSX 96xG3 1492393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8551), //PAX 24XG3 1493393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8552), //PAX 32XG3 1494393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8553), //PAX 48XG3 1495393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8554), //PAX 64XG3 1496393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8555), //PAX 80XG3 1497393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8556), //PAX 96XG3 1498393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8561), //PFXL 24XG3 1499393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8562), //PFXL 32XG3 1500393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8563), //PFXL 48XG3 1501393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8564), //PFXL 64XG3 1502393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8565), //PFXL 80XG3 1503393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8566), //PFXL 96XG3 1504393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8571), //PFXI 24XG3 1505393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8572), //PFXI 32XG3 1506393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8573), //PFXI 48XG3 1507393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8574), //PFXI 64XG3 1508393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8575), //PFXI 80XG3 1509393958d0SLogan Gunthorpe SWITCHTEC_PCI_DEVICE(0x8576), //PFXI 96XG3 1510080b47deSLogan Gunthorpe {0} 1511080b47deSLogan Gunthorpe }; 1512080b47deSLogan Gunthorpe MODULE_DEVICE_TABLE(pci, switchtec_pci_tbl); 1513080b47deSLogan Gunthorpe 1514080b47deSLogan Gunthorpe static struct pci_driver switchtec_pci_driver = { 1515080b47deSLogan Gunthorpe .name = KBUILD_MODNAME, 1516080b47deSLogan Gunthorpe .id_table = switchtec_pci_tbl, 1517080b47deSLogan Gunthorpe .probe = switchtec_pci_probe, 1518080b47deSLogan Gunthorpe .remove = switchtec_pci_remove, 1519080b47deSLogan Gunthorpe }; 1520080b47deSLogan Gunthorpe 1521080b47deSLogan Gunthorpe static int __init switchtec_init(void) 1522080b47deSLogan Gunthorpe { 1523080b47deSLogan Gunthorpe int rc; 1524080b47deSLogan Gunthorpe 1525080b47deSLogan Gunthorpe rc = alloc_chrdev_region(&switchtec_devt, 0, max_devices, 1526080b47deSLogan Gunthorpe "switchtec"); 1527080b47deSLogan Gunthorpe if (rc) 1528080b47deSLogan Gunthorpe return rc; 1529080b47deSLogan Gunthorpe 1530080b47deSLogan Gunthorpe switchtec_class = class_create(THIS_MODULE, "switchtec"); 1531080b47deSLogan Gunthorpe if (IS_ERR(switchtec_class)) { 1532080b47deSLogan Gunthorpe rc = PTR_ERR(switchtec_class); 1533080b47deSLogan Gunthorpe goto err_create_class; 1534080b47deSLogan Gunthorpe } 1535080b47deSLogan Gunthorpe 1536080b47deSLogan Gunthorpe rc = pci_register_driver(&switchtec_pci_driver); 1537080b47deSLogan Gunthorpe if (rc) 1538080b47deSLogan Gunthorpe goto err_pci_register; 1539080b47deSLogan Gunthorpe 1540080b47deSLogan Gunthorpe pr_info(KBUILD_MODNAME ": loaded.\n"); 1541080b47deSLogan Gunthorpe 1542080b47deSLogan Gunthorpe return 0; 1543080b47deSLogan Gunthorpe 1544080b47deSLogan Gunthorpe err_pci_register: 1545080b47deSLogan Gunthorpe class_destroy(switchtec_class); 1546080b47deSLogan Gunthorpe 1547080b47deSLogan Gunthorpe err_create_class: 1548080b47deSLogan Gunthorpe unregister_chrdev_region(switchtec_devt, max_devices); 1549080b47deSLogan Gunthorpe 1550080b47deSLogan Gunthorpe return rc; 1551080b47deSLogan Gunthorpe } 1552080b47deSLogan Gunthorpe module_init(switchtec_init); 1553080b47deSLogan Gunthorpe 1554080b47deSLogan Gunthorpe static void __exit switchtec_exit(void) 1555080b47deSLogan Gunthorpe { 1556080b47deSLogan Gunthorpe pci_unregister_driver(&switchtec_pci_driver); 1557080b47deSLogan Gunthorpe class_destroy(switchtec_class); 1558080b47deSLogan Gunthorpe unregister_chrdev_region(switchtec_devt, max_devices); 1559080b47deSLogan Gunthorpe ida_destroy(&switchtec_minor_ida); 1560080b47deSLogan Gunthorpe 1561080b47deSLogan Gunthorpe pr_info(KBUILD_MODNAME ": unloaded.\n"); 1562080b47deSLogan Gunthorpe } 1563080b47deSLogan Gunthorpe module_exit(switchtec_exit); 1564