1888 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Microsemi Switchtec(tm) PCIe Management Driver4 * Copyright (c) 2017, Microsemi Corporation5 */6 7#include <linux/switchtec.h>8#include <linux/switchtec_ioctl.h>9 10#include <linux/interrupt.h>11#include <linux/module.h>12#include <linux/fs.h>13#include <linux/uaccess.h>14#include <linux/poll.h>15#include <linux/wait.h>16#include <linux/io-64-nonatomic-lo-hi.h>17#include <linux/nospec.h>18 19MODULE_DESCRIPTION("Microsemi Switchtec(tm) PCIe Management Driver");20MODULE_VERSION("0.1");21MODULE_LICENSE("GPL");22MODULE_AUTHOR("Microsemi Corporation");23 24static int max_devices = 16;25module_param(max_devices, int, 0644);26MODULE_PARM_DESC(max_devices, "max number of switchtec device instances");27 28static bool use_dma_mrpc = true;29module_param(use_dma_mrpc, bool, 0644);30MODULE_PARM_DESC(use_dma_mrpc,31 "Enable the use of the DMA MRPC feature");32 33static int nirqs = 32;34module_param(nirqs, int, 0644);35MODULE_PARM_DESC(nirqs, "number of interrupts to allocate (more may be useful for NTB applications)");36 37static dev_t switchtec_devt;38static DEFINE_IDA(switchtec_minor_ida);39 40const struct class switchtec_class = {41 .name = "switchtec",42};43EXPORT_SYMBOL_GPL(switchtec_class);44 45enum mrpc_state {46 MRPC_IDLE = 0,47 MRPC_QUEUED,48 MRPC_RUNNING,49 MRPC_DONE,50 MRPC_IO_ERROR,51};52 53struct switchtec_user {54 struct switchtec_dev *stdev;55 56 enum mrpc_state state;57 58 wait_queue_head_t cmd_comp;59 struct kref kref;60 struct list_head list;61 62 bool cmd_done;63 u32 cmd;64 u32 status;65 u32 return_code;66 size_t data_len;67 size_t read_len;68 unsigned char data[SWITCHTEC_MRPC_PAYLOAD_SIZE];69 int event_cnt;70};71 72/*73 * The MMIO reads to the device_id register should always return the device ID74 * of the device, otherwise the firmware is probably stuck or unreachable75 * due to a firmware reset which clears PCI state including the BARs and Memory76 * Space Enable bits.77 */78static int is_firmware_running(struct switchtec_dev *stdev)79{80 u32 device = ioread32(&stdev->mmio_sys_info->device_id);81 82 return stdev->pdev->device == device;83}84 85static struct switchtec_user *stuser_create(struct switchtec_dev *stdev)86{87 struct switchtec_user *stuser;88 89 stuser = kzalloc(sizeof(*stuser), GFP_KERNEL);90 if (!stuser)91 return ERR_PTR(-ENOMEM);92 93 get_device(&stdev->dev);94 stuser->stdev = stdev;95 kref_init(&stuser->kref);96 INIT_LIST_HEAD(&stuser->list);97 init_waitqueue_head(&stuser->cmd_comp);98 stuser->event_cnt = atomic_read(&stdev->event_cnt);99 100 dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser);101 102 return stuser;103}104 105static void stuser_free(struct kref *kref)106{107 struct switchtec_user *stuser;108 109 stuser = container_of(kref, struct switchtec_user, kref);110 111 dev_dbg(&stuser->stdev->dev, "%s: %p\n", __func__, stuser);112 113 put_device(&stuser->stdev->dev);114 kfree(stuser);115}116 117static void stuser_put(struct switchtec_user *stuser)118{119 kref_put(&stuser->kref, stuser_free);120}121 122static void stuser_set_state(struct switchtec_user *stuser,123 enum mrpc_state state)124{125 /* requires the mrpc_mutex to already be held when called */126 127 static const char * const state_names[] = {128 [MRPC_IDLE] = "IDLE",129 [MRPC_QUEUED] = "QUEUED",130 [MRPC_RUNNING] = "RUNNING",131 [MRPC_DONE] = "DONE",132 [MRPC_IO_ERROR] = "IO_ERROR",133 };134 135 stuser->state = state;136 137 dev_dbg(&stuser->stdev->dev, "stuser state %p -> %s",138 stuser, state_names[state]);139}140 141static void mrpc_complete_cmd(struct switchtec_dev *stdev);142 143static void flush_wc_buf(struct switchtec_dev *stdev)144{145 struct ntb_dbmsg_regs __iomem *mmio_dbmsg;146 147 /*148 * odb (outbound doorbell) register is processed by low latency149 * hardware and w/o side effect150 */151 mmio_dbmsg = (void __iomem *)stdev->mmio_ntb +152 SWITCHTEC_NTB_REG_DBMSG_OFFSET;153 ioread32(&mmio_dbmsg->odb);154}155 156static void mrpc_cmd_submit(struct switchtec_dev *stdev)157{158 /* requires the mrpc_mutex to already be held when called */159 160 struct switchtec_user *stuser;161 162 if (stdev->mrpc_busy)163 return;164 165 if (list_empty(&stdev->mrpc_queue))166 return;167 168 stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user,169 list);170 171 if (stdev->dma_mrpc) {172 stdev->dma_mrpc->status = SWITCHTEC_MRPC_STATUS_INPROGRESS;173 memset(stdev->dma_mrpc->data, 0xFF, SWITCHTEC_MRPC_PAYLOAD_SIZE);174 }175 176 stuser_set_state(stuser, MRPC_RUNNING);177 stdev->mrpc_busy = 1;178 memcpy_toio(&stdev->mmio_mrpc->input_data,179 stuser->data, stuser->data_len);180 flush_wc_buf(stdev);181 iowrite32(stuser->cmd, &stdev->mmio_mrpc->cmd);182 183 schedule_delayed_work(&stdev->mrpc_timeout,184 msecs_to_jiffies(500));185}186 187static int mrpc_queue_cmd(struct switchtec_user *stuser)188{189 /* requires the mrpc_mutex to already be held when called */190 191 struct switchtec_dev *stdev = stuser->stdev;192 193 kref_get(&stuser->kref);194 stuser->read_len = sizeof(stuser->data);195 stuser_set_state(stuser, MRPC_QUEUED);196 stuser->cmd_done = false;197 list_add_tail(&stuser->list, &stdev->mrpc_queue);198 199 mrpc_cmd_submit(stdev);200 201 return 0;202}203 204static void mrpc_cleanup_cmd(struct switchtec_dev *stdev)205{206 /* requires the mrpc_mutex to already be held when called */207 208 struct switchtec_user *stuser = list_entry(stdev->mrpc_queue.next,209 struct switchtec_user, list);210 211 stuser->cmd_done = true;212 wake_up_interruptible(&stuser->cmd_comp);213 list_del_init(&stuser->list);214 stuser_put(stuser);215 stdev->mrpc_busy = 0;216 217 mrpc_cmd_submit(stdev);218}219 220static void mrpc_complete_cmd(struct switchtec_dev *stdev)221{222 /* requires the mrpc_mutex to already be held when called */223 224 struct switchtec_user *stuser;225 226 if (list_empty(&stdev->mrpc_queue))227 return;228 229 stuser = list_entry(stdev->mrpc_queue.next, struct switchtec_user,230 list);231 232 if (stdev->dma_mrpc)233 stuser->status = stdev->dma_mrpc->status;234 else235 stuser->status = ioread32(&stdev->mmio_mrpc->status);236 237 if (stuser->status == SWITCHTEC_MRPC_STATUS_INPROGRESS)238 return;239 240 stuser_set_state(stuser, MRPC_DONE);241 stuser->return_code = 0;242 243 if (stuser->status != SWITCHTEC_MRPC_STATUS_DONE &&244 stuser->status != SWITCHTEC_MRPC_STATUS_ERROR)245 goto out;246 247 if (stdev->dma_mrpc)248 stuser->return_code = stdev->dma_mrpc->rtn_code;249 else250 stuser->return_code = ioread32(&stdev->mmio_mrpc->ret_value);251 if (stuser->return_code != 0)252 goto out;253 254 if (stdev->dma_mrpc)255 memcpy(stuser->data, &stdev->dma_mrpc->data,256 stuser->read_len);257 else258 memcpy_fromio(stuser->data, &stdev->mmio_mrpc->output_data,259 stuser->read_len);260out:261 mrpc_cleanup_cmd(stdev);262}263 264static void mrpc_event_work(struct work_struct *work)265{266 struct switchtec_dev *stdev;267 268 stdev = container_of(work, struct switchtec_dev, mrpc_work);269 270 dev_dbg(&stdev->dev, "%s\n", __func__);271 272 mutex_lock(&stdev->mrpc_mutex);273 cancel_delayed_work(&stdev->mrpc_timeout);274 mrpc_complete_cmd(stdev);275 mutex_unlock(&stdev->mrpc_mutex);276}277 278static void mrpc_error_complete_cmd(struct switchtec_dev *stdev)279{280 /* requires the mrpc_mutex to already be held when called */281 282 struct switchtec_user *stuser;283 284 if (list_empty(&stdev->mrpc_queue))285 return;286 287 stuser = list_entry(stdev->mrpc_queue.next,288 struct switchtec_user, list);289 290 stuser_set_state(stuser, MRPC_IO_ERROR);291 292 mrpc_cleanup_cmd(stdev);293}294 295static void mrpc_timeout_work(struct work_struct *work)296{297 struct switchtec_dev *stdev;298 u32 status;299 300 stdev = container_of(work, struct switchtec_dev, mrpc_timeout.work);301 302 dev_dbg(&stdev->dev, "%s\n", __func__);303 304 mutex_lock(&stdev->mrpc_mutex);305 306 if (!is_firmware_running(stdev)) {307 mrpc_error_complete_cmd(stdev);308 goto out;309 }310 311 if (stdev->dma_mrpc)312 status = stdev->dma_mrpc->status;313 else314 status = ioread32(&stdev->mmio_mrpc->status);315 if (status == SWITCHTEC_MRPC_STATUS_INPROGRESS) {316 schedule_delayed_work(&stdev->mrpc_timeout,317 msecs_to_jiffies(500));318 goto out;319 }320 321 mrpc_complete_cmd(stdev);322out:323 mutex_unlock(&stdev->mrpc_mutex);324}325 326static ssize_t device_version_show(struct device *dev,327 struct device_attribute *attr, char *buf)328{329 struct switchtec_dev *stdev = to_stdev(dev);330 u32 ver;331 332 ver = ioread32(&stdev->mmio_sys_info->device_version);333 334 return sysfs_emit(buf, "%x\n", ver);335}336static DEVICE_ATTR_RO(device_version);337 338static ssize_t fw_version_show(struct device *dev,339 struct device_attribute *attr, char *buf)340{341 struct switchtec_dev *stdev = to_stdev(dev);342 u32 ver;343 344 ver = ioread32(&stdev->mmio_sys_info->firmware_version);345 346 return sysfs_emit(buf, "%08x\n", ver);347}348static DEVICE_ATTR_RO(fw_version);349 350static ssize_t io_string_show(char *buf, void __iomem *attr, size_t len)351{352 int i;353 354 memcpy_fromio(buf, attr, len);355 buf[len] = '\n';356 buf[len + 1] = 0;357 358 for (i = len - 1; i > 0; i--) {359 if (buf[i] != ' ')360 break;361 buf[i] = '\n';362 buf[i + 1] = 0;363 }364 365 return strlen(buf);366}367 368#define DEVICE_ATTR_SYS_INFO_STR(field) \369static ssize_t field ## _show(struct device *dev, \370 struct device_attribute *attr, char *buf) \371{ \372 struct switchtec_dev *stdev = to_stdev(dev); \373 struct sys_info_regs __iomem *si = stdev->mmio_sys_info; \374 if (stdev->gen == SWITCHTEC_GEN3) \375 return io_string_show(buf, &si->gen3.field, \376 sizeof(si->gen3.field)); \377 else if (stdev->gen >= SWITCHTEC_GEN4) \378 return io_string_show(buf, &si->gen4.field, \379 sizeof(si->gen4.field)); \380 else \381 return -EOPNOTSUPP; \382} \383\384static DEVICE_ATTR_RO(field)385 386DEVICE_ATTR_SYS_INFO_STR(vendor_id);387DEVICE_ATTR_SYS_INFO_STR(product_id);388DEVICE_ATTR_SYS_INFO_STR(product_revision);389 390static ssize_t component_vendor_show(struct device *dev,391 struct device_attribute *attr, char *buf)392{393 struct switchtec_dev *stdev = to_stdev(dev);394 struct sys_info_regs __iomem *si = stdev->mmio_sys_info;395 396 /* component_vendor field not supported after gen3 */397 if (stdev->gen != SWITCHTEC_GEN3)398 return sysfs_emit(buf, "none\n");399 400 return io_string_show(buf, &si->gen3.component_vendor,401 sizeof(si->gen3.component_vendor));402}403static DEVICE_ATTR_RO(component_vendor);404 405static ssize_t component_id_show(struct device *dev,406 struct device_attribute *attr, char *buf)407{408 struct switchtec_dev *stdev = to_stdev(dev);409 int id = ioread16(&stdev->mmio_sys_info->gen3.component_id);410 411 /* component_id field not supported after gen3 */412 if (stdev->gen != SWITCHTEC_GEN3)413 return sysfs_emit(buf, "none\n");414 415 return sysfs_emit(buf, "PM%04X\n", id);416}417static DEVICE_ATTR_RO(component_id);418 419static ssize_t component_revision_show(struct device *dev,420 struct device_attribute *attr, char *buf)421{422 struct switchtec_dev *stdev = to_stdev(dev);423 int rev = ioread8(&stdev->mmio_sys_info->gen3.component_revision);424 425 /* component_revision field not supported after gen3 */426 if (stdev->gen != SWITCHTEC_GEN3)427 return sysfs_emit(buf, "255\n");428 429 return sysfs_emit(buf, "%d\n", rev);430}431static DEVICE_ATTR_RO(component_revision);432 433static ssize_t partition_show(struct device *dev,434 struct device_attribute *attr, char *buf)435{436 struct switchtec_dev *stdev = to_stdev(dev);437 438 return sysfs_emit(buf, "%d\n", stdev->partition);439}440static DEVICE_ATTR_RO(partition);441 442static ssize_t partition_count_show(struct device *dev,443 struct device_attribute *attr, char *buf)444{445 struct switchtec_dev *stdev = to_stdev(dev);446 447 return sysfs_emit(buf, "%d\n", stdev->partition_count);448}449static DEVICE_ATTR_RO(partition_count);450 451static struct attribute *switchtec_device_attrs[] = {452 &dev_attr_device_version.attr,453 &dev_attr_fw_version.attr,454 &dev_attr_vendor_id.attr,455 &dev_attr_product_id.attr,456 &dev_attr_product_revision.attr,457 &dev_attr_component_vendor.attr,458 &dev_attr_component_id.attr,459 &dev_attr_component_revision.attr,460 &dev_attr_partition.attr,461 &dev_attr_partition_count.attr,462 NULL,463};464 465ATTRIBUTE_GROUPS(switchtec_device);466 467static int switchtec_dev_open(struct inode *inode, struct file *filp)468{469 struct switchtec_dev *stdev;470 struct switchtec_user *stuser;471 472 stdev = container_of(inode->i_cdev, struct switchtec_dev, cdev);473 474 stuser = stuser_create(stdev);475 if (IS_ERR(stuser))476 return PTR_ERR(stuser);477 478 filp->private_data = stuser;479 stream_open(inode, filp);480 481 dev_dbg(&stdev->dev, "%s: %p\n", __func__, stuser);482 483 return 0;484}485 486static int switchtec_dev_release(struct inode *inode, struct file *filp)487{488 struct switchtec_user *stuser = filp->private_data;489 490 stuser_put(stuser);491 492 return 0;493}494 495static int lock_mutex_and_test_alive(struct switchtec_dev *stdev)496{497 if (mutex_lock_interruptible(&stdev->mrpc_mutex))498 return -EINTR;499 500 if (!stdev->alive) {501 mutex_unlock(&stdev->mrpc_mutex);502 return -ENODEV;503 }504 505 return 0;506}507 508static ssize_t switchtec_dev_write(struct file *filp, const char __user *data,509 size_t size, loff_t *off)510{511 struct switchtec_user *stuser = filp->private_data;512 struct switchtec_dev *stdev = stuser->stdev;513 int rc;514 515 if (size < sizeof(stuser->cmd) ||516 size > sizeof(stuser->cmd) + sizeof(stuser->data))517 return -EINVAL;518 519 stuser->data_len = size - sizeof(stuser->cmd);520 521 rc = lock_mutex_and_test_alive(stdev);522 if (rc)523 return rc;524 525 if (stuser->state != MRPC_IDLE) {526 rc = -EBADE;527 goto out;528 }529 530 rc = copy_from_user(&stuser->cmd, data, sizeof(stuser->cmd));531 if (rc) {532 rc = -EFAULT;533 goto out;534 }535 if (((MRPC_CMD_ID(stuser->cmd) == MRPC_GAS_WRITE) ||536 (MRPC_CMD_ID(stuser->cmd) == MRPC_GAS_READ)) &&537 !capable(CAP_SYS_ADMIN)) {538 rc = -EPERM;539 goto out;540 }541 542 data += sizeof(stuser->cmd);543 rc = copy_from_user(&stuser->data, data, size - sizeof(stuser->cmd));544 if (rc) {545 rc = -EFAULT;546 goto out;547 }548 549 rc = mrpc_queue_cmd(stuser);550 551out:552 mutex_unlock(&stdev->mrpc_mutex);553 554 if (rc)555 return rc;556 557 return size;558}559 560static ssize_t switchtec_dev_read(struct file *filp, char __user *data,561 size_t size, loff_t *off)562{563 struct switchtec_user *stuser = filp->private_data;564 struct switchtec_dev *stdev = stuser->stdev;565 int rc;566 567 if (size < sizeof(stuser->cmd) ||568 size > sizeof(stuser->cmd) + sizeof(stuser->data))569 return -EINVAL;570 571 rc = lock_mutex_and_test_alive(stdev);572 if (rc)573 return rc;574 575 if (stuser->state == MRPC_IDLE) {576 mutex_unlock(&stdev->mrpc_mutex);577 return -EBADE;578 }579 580 stuser->read_len = size - sizeof(stuser->return_code);581 582 mutex_unlock(&stdev->mrpc_mutex);583 584 if (filp->f_flags & O_NONBLOCK) {585 if (!stuser->cmd_done)586 return -EAGAIN;587 } else {588 rc = wait_event_interruptible(stuser->cmd_comp,589 stuser->cmd_done);590 if (rc < 0)591 return rc;592 }593 594 rc = lock_mutex_and_test_alive(stdev);595 if (rc)596 return rc;597 598 if (stuser->state == MRPC_IO_ERROR) {599 mutex_unlock(&stdev->mrpc_mutex);600 return -EIO;601 }602 603 if (stuser->state != MRPC_DONE) {604 mutex_unlock(&stdev->mrpc_mutex);605 return -EBADE;606 }607 608 rc = copy_to_user(data, &stuser->return_code,609 sizeof(stuser->return_code));610 if (rc) {611 mutex_unlock(&stdev->mrpc_mutex);612 return -EFAULT;613 }614 615 data += sizeof(stuser->return_code);616 rc = copy_to_user(data, &stuser->data,617 size - sizeof(stuser->return_code));618 if (rc) {619 mutex_unlock(&stdev->mrpc_mutex);620 return -EFAULT;621 }622 623 stuser_set_state(stuser, MRPC_IDLE);624 625 mutex_unlock(&stdev->mrpc_mutex);626 627 if (stuser->status == SWITCHTEC_MRPC_STATUS_DONE ||628 stuser->status == SWITCHTEC_MRPC_STATUS_ERROR)629 return size;630 else if (stuser->status == SWITCHTEC_MRPC_STATUS_INTERRUPTED)631 return -ENXIO;632 else633 return -EBADMSG;634}635 636static __poll_t switchtec_dev_poll(struct file *filp, poll_table *wait)637{638 struct switchtec_user *stuser = filp->private_data;639 struct switchtec_dev *stdev = stuser->stdev;640 __poll_t ret = 0;641 642 poll_wait(filp, &stuser->cmd_comp, wait);643 poll_wait(filp, &stdev->event_wq, wait);644 645 if (lock_mutex_and_test_alive(stdev))646 return EPOLLIN | EPOLLRDHUP | EPOLLOUT | EPOLLERR | EPOLLHUP;647 648 mutex_unlock(&stdev->mrpc_mutex);649 650 if (stuser->cmd_done)651 ret |= EPOLLIN | EPOLLRDNORM;652 653 if (stuser->event_cnt != atomic_read(&stdev->event_cnt))654 ret |= EPOLLPRI | EPOLLRDBAND;655 656 return ret;657}658 659static int ioctl_flash_info(struct switchtec_dev *stdev,660 struct switchtec_ioctl_flash_info __user *uinfo)661{662 struct switchtec_ioctl_flash_info info = {0};663 struct flash_info_regs __iomem *fi = stdev->mmio_flash_info;664 665 if (stdev->gen == SWITCHTEC_GEN3) {666 info.flash_length = ioread32(&fi->gen3.flash_length);667 info.num_partitions = SWITCHTEC_NUM_PARTITIONS_GEN3;668 } else if (stdev->gen >= SWITCHTEC_GEN4) {669 info.flash_length = ioread32(&fi->gen4.flash_length);670 info.num_partitions = SWITCHTEC_NUM_PARTITIONS_GEN4;671 } else {672 return -EOPNOTSUPP;673 }674 675 if (copy_to_user(uinfo, &info, sizeof(info)))676 return -EFAULT;677 678 return 0;679}680 681static void set_fw_info_part(struct switchtec_ioctl_flash_part_info *info,682 struct partition_info __iomem *pi)683{684 info->address = ioread32(&pi->address);685 info->length = ioread32(&pi->length);686}687 688static int flash_part_info_gen3(struct switchtec_dev *stdev,689 struct switchtec_ioctl_flash_part_info *info)690{691 struct flash_info_regs_gen3 __iomem *fi =692 &stdev->mmio_flash_info->gen3;693 struct sys_info_regs_gen3 __iomem *si = &stdev->mmio_sys_info->gen3;694 u32 active_addr = -1;695 696 switch (info->flash_partition) {697 case SWITCHTEC_IOCTL_PART_CFG0:698 active_addr = ioread32(&fi->active_cfg);699 set_fw_info_part(info, &fi->cfg0);700 if (ioread16(&si->cfg_running) == SWITCHTEC_GEN3_CFG0_RUNNING)701 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;702 break;703 case SWITCHTEC_IOCTL_PART_CFG1:704 active_addr = ioread32(&fi->active_cfg);705 set_fw_info_part(info, &fi->cfg1);706 if (ioread16(&si->cfg_running) == SWITCHTEC_GEN3_CFG1_RUNNING)707 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;708 break;709 case SWITCHTEC_IOCTL_PART_IMG0:710 active_addr = ioread32(&fi->active_img);711 set_fw_info_part(info, &fi->img0);712 if (ioread16(&si->img_running) == SWITCHTEC_GEN3_IMG0_RUNNING)713 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;714 break;715 case SWITCHTEC_IOCTL_PART_IMG1:716 active_addr = ioread32(&fi->active_img);717 set_fw_info_part(info, &fi->img1);718 if (ioread16(&si->img_running) == SWITCHTEC_GEN3_IMG1_RUNNING)719 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;720 break;721 case SWITCHTEC_IOCTL_PART_NVLOG:722 set_fw_info_part(info, &fi->nvlog);723 break;724 case SWITCHTEC_IOCTL_PART_VENDOR0:725 set_fw_info_part(info, &fi->vendor[0]);726 break;727 case SWITCHTEC_IOCTL_PART_VENDOR1:728 set_fw_info_part(info, &fi->vendor[1]);729 break;730 case SWITCHTEC_IOCTL_PART_VENDOR2:731 set_fw_info_part(info, &fi->vendor[2]);732 break;733 case SWITCHTEC_IOCTL_PART_VENDOR3:734 set_fw_info_part(info, &fi->vendor[3]);735 break;736 case SWITCHTEC_IOCTL_PART_VENDOR4:737 set_fw_info_part(info, &fi->vendor[4]);738 break;739 case SWITCHTEC_IOCTL_PART_VENDOR5:740 set_fw_info_part(info, &fi->vendor[5]);741 break;742 case SWITCHTEC_IOCTL_PART_VENDOR6:743 set_fw_info_part(info, &fi->vendor[6]);744 break;745 case SWITCHTEC_IOCTL_PART_VENDOR7:746 set_fw_info_part(info, &fi->vendor[7]);747 break;748 default:749 return -EINVAL;750 }751 752 if (info->address == active_addr)753 info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;754 755 return 0;756}757 758static int flash_part_info_gen4(struct switchtec_dev *stdev,759 struct switchtec_ioctl_flash_part_info *info)760{761 struct flash_info_regs_gen4 __iomem *fi = &stdev->mmio_flash_info->gen4;762 struct sys_info_regs_gen4 __iomem *si = &stdev->mmio_sys_info->gen4;763 struct active_partition_info_gen4 __iomem *af = &fi->active_flag;764 765 switch (info->flash_partition) {766 case SWITCHTEC_IOCTL_PART_MAP_0:767 set_fw_info_part(info, &fi->map0);768 break;769 case SWITCHTEC_IOCTL_PART_MAP_1:770 set_fw_info_part(info, &fi->map1);771 break;772 case SWITCHTEC_IOCTL_PART_KEY_0:773 set_fw_info_part(info, &fi->key0);774 if (ioread8(&af->key) == SWITCHTEC_GEN4_KEY0_ACTIVE)775 info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;776 if (ioread16(&si->key_running) == SWITCHTEC_GEN4_KEY0_RUNNING)777 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;778 break;779 case SWITCHTEC_IOCTL_PART_KEY_1:780 set_fw_info_part(info, &fi->key1);781 if (ioread8(&af->key) == SWITCHTEC_GEN4_KEY1_ACTIVE)782 info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;783 if (ioread16(&si->key_running) == SWITCHTEC_GEN4_KEY1_RUNNING)784 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;785 break;786 case SWITCHTEC_IOCTL_PART_BL2_0:787 set_fw_info_part(info, &fi->bl2_0);788 if (ioread8(&af->bl2) == SWITCHTEC_GEN4_BL2_0_ACTIVE)789 info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;790 if (ioread16(&si->bl2_running) == SWITCHTEC_GEN4_BL2_0_RUNNING)791 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;792 break;793 case SWITCHTEC_IOCTL_PART_BL2_1:794 set_fw_info_part(info, &fi->bl2_1);795 if (ioread8(&af->bl2) == SWITCHTEC_GEN4_BL2_1_ACTIVE)796 info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;797 if (ioread16(&si->bl2_running) == SWITCHTEC_GEN4_BL2_1_RUNNING)798 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;799 break;800 case SWITCHTEC_IOCTL_PART_CFG0:801 set_fw_info_part(info, &fi->cfg0);802 if (ioread8(&af->cfg) == SWITCHTEC_GEN4_CFG0_ACTIVE)803 info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;804 if (ioread16(&si->cfg_running) == SWITCHTEC_GEN4_CFG0_RUNNING)805 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;806 break;807 case SWITCHTEC_IOCTL_PART_CFG1:808 set_fw_info_part(info, &fi->cfg1);809 if (ioread8(&af->cfg) == SWITCHTEC_GEN4_CFG1_ACTIVE)810 info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;811 if (ioread16(&si->cfg_running) == SWITCHTEC_GEN4_CFG1_RUNNING)812 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;813 break;814 case SWITCHTEC_IOCTL_PART_IMG0:815 set_fw_info_part(info, &fi->img0);816 if (ioread8(&af->img) == SWITCHTEC_GEN4_IMG0_ACTIVE)817 info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;818 if (ioread16(&si->img_running) == SWITCHTEC_GEN4_IMG0_RUNNING)819 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;820 break;821 case SWITCHTEC_IOCTL_PART_IMG1:822 set_fw_info_part(info, &fi->img1);823 if (ioread8(&af->img) == SWITCHTEC_GEN4_IMG1_ACTIVE)824 info->active |= SWITCHTEC_IOCTL_PART_ACTIVE;825 if (ioread16(&si->img_running) == SWITCHTEC_GEN4_IMG1_RUNNING)826 info->active |= SWITCHTEC_IOCTL_PART_RUNNING;827 break;828 case SWITCHTEC_IOCTL_PART_NVLOG:829 set_fw_info_part(info, &fi->nvlog);830 break;831 case SWITCHTEC_IOCTL_PART_VENDOR0:832 set_fw_info_part(info, &fi->vendor[0]);833 break;834 case SWITCHTEC_IOCTL_PART_VENDOR1:835 set_fw_info_part(info, &fi->vendor[1]);836 break;837 case SWITCHTEC_IOCTL_PART_VENDOR2:838 set_fw_info_part(info, &fi->vendor[2]);839 break;840 case SWITCHTEC_IOCTL_PART_VENDOR3:841 set_fw_info_part(info, &fi->vendor[3]);842 break;843 case SWITCHTEC_IOCTL_PART_VENDOR4:844 set_fw_info_part(info, &fi->vendor[4]);845 break;846 case SWITCHTEC_IOCTL_PART_VENDOR5:847 set_fw_info_part(info, &fi->vendor[5]);848 break;849 case SWITCHTEC_IOCTL_PART_VENDOR6:850 set_fw_info_part(info, &fi->vendor[6]);851 break;852 case SWITCHTEC_IOCTL_PART_VENDOR7:853 set_fw_info_part(info, &fi->vendor[7]);854 break;855 default:856 return -EINVAL;857 }858 859 return 0;860}861 862static int ioctl_flash_part_info(struct switchtec_dev *stdev,863 struct switchtec_ioctl_flash_part_info __user *uinfo)864{865 int ret;866 struct switchtec_ioctl_flash_part_info info = {0};867 868 if (copy_from_user(&info, uinfo, sizeof(info)))869 return -EFAULT;870 871 if (stdev->gen == SWITCHTEC_GEN3) {872 ret = flash_part_info_gen3(stdev, &info);873 if (ret)874 return ret;875 } else if (stdev->gen >= SWITCHTEC_GEN4) {876 ret = flash_part_info_gen4(stdev, &info);877 if (ret)878 return ret;879 } else {880 return -EOPNOTSUPP;881 }882 883 if (copy_to_user(uinfo, &info, sizeof(info)))884 return -EFAULT;885 886 return 0;887}888 889static int ioctl_event_summary(struct switchtec_dev *stdev,890 struct switchtec_user *stuser,891 struct switchtec_ioctl_event_summary __user *usum,892 size_t size)893{894 struct switchtec_ioctl_event_summary *s;895 int i;896 u32 reg;897 int ret = 0;898 899 s = kzalloc(sizeof(*s), GFP_KERNEL);900 if (!s)901 return -ENOMEM;902 903 s->global = ioread32(&stdev->mmio_sw_event->global_summary);904 s->part_bitmap = ioread64(&stdev->mmio_sw_event->part_event_bitmap);905 s->local_part = ioread32(&stdev->mmio_part_cfg->part_event_summary);906 907 for (i = 0; i < stdev->partition_count; i++) {908 reg = ioread32(&stdev->mmio_part_cfg_all[i].part_event_summary);909 s->part[i] = reg;910 }911 912 for (i = 0; i < stdev->pff_csr_count; i++) {913 reg = ioread32(&stdev->mmio_pff_csr[i].pff_event_summary);914 s->pff[i] = reg;915 }916 917 if (copy_to_user(usum, s, size)) {918 ret = -EFAULT;919 goto error_case;920 }921 922 stuser->event_cnt = atomic_read(&stdev->event_cnt);923 924error_case:925 kfree(s);926 return ret;927}928 929static u32 __iomem *global_ev_reg(struct switchtec_dev *stdev,930 size_t offset, int index)931{932 return (void __iomem *)stdev->mmio_sw_event + offset;933}934 935static u32 __iomem *part_ev_reg(struct switchtec_dev *stdev,936 size_t offset, int index)937{938 return (void __iomem *)&stdev->mmio_part_cfg_all[index] + offset;939}940 941static u32 __iomem *pff_ev_reg(struct switchtec_dev *stdev,942 size_t offset, int index)943{944 return (void __iomem *)&stdev->mmio_pff_csr[index] + offset;945}946 947#define EV_GLB(i, r)[i] = {offsetof(struct sw_event_regs, r), global_ev_reg}948#define EV_PAR(i, r)[i] = {offsetof(struct part_cfg_regs, r), part_ev_reg}949#define EV_PFF(i, r)[i] = {offsetof(struct pff_csr_regs, r), pff_ev_reg}950 951static const struct event_reg {952 size_t offset;953 u32 __iomem *(*map_reg)(struct switchtec_dev *stdev,954 size_t offset, int index);955} event_regs[] = {956 EV_GLB(SWITCHTEC_IOCTL_EVENT_STACK_ERROR, stack_error_event_hdr),957 EV_GLB(SWITCHTEC_IOCTL_EVENT_PPU_ERROR, ppu_error_event_hdr),958 EV_GLB(SWITCHTEC_IOCTL_EVENT_ISP_ERROR, isp_error_event_hdr),959 EV_GLB(SWITCHTEC_IOCTL_EVENT_SYS_RESET, sys_reset_event_hdr),960 EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_EXC, fw_exception_hdr),961 EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_NMI, fw_nmi_hdr),962 EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_NON_FATAL, fw_non_fatal_hdr),963 EV_GLB(SWITCHTEC_IOCTL_EVENT_FW_FATAL, fw_fatal_hdr),964 EV_GLB(SWITCHTEC_IOCTL_EVENT_TWI_MRPC_COMP, twi_mrpc_comp_hdr),965 EV_GLB(SWITCHTEC_IOCTL_EVENT_TWI_MRPC_COMP_ASYNC,966 twi_mrpc_comp_async_hdr),967 EV_GLB(SWITCHTEC_IOCTL_EVENT_CLI_MRPC_COMP, cli_mrpc_comp_hdr),968 EV_GLB(SWITCHTEC_IOCTL_EVENT_CLI_MRPC_COMP_ASYNC,969 cli_mrpc_comp_async_hdr),970 EV_GLB(SWITCHTEC_IOCTL_EVENT_GPIO_INT, gpio_interrupt_hdr),971 EV_GLB(SWITCHTEC_IOCTL_EVENT_GFMS, gfms_event_hdr),972 EV_PAR(SWITCHTEC_IOCTL_EVENT_PART_RESET, part_reset_hdr),973 EV_PAR(SWITCHTEC_IOCTL_EVENT_MRPC_COMP, mrpc_comp_hdr),974 EV_PAR(SWITCHTEC_IOCTL_EVENT_MRPC_COMP_ASYNC, mrpc_comp_async_hdr),975 EV_PAR(SWITCHTEC_IOCTL_EVENT_DYN_PART_BIND_COMP, dyn_binding_hdr),976 EV_PAR(SWITCHTEC_IOCTL_EVENT_INTERCOMM_REQ_NOTIFY,977 intercomm_notify_hdr),978 EV_PFF(SWITCHTEC_IOCTL_EVENT_AER_IN_P2P, aer_in_p2p_hdr),979 EV_PFF(SWITCHTEC_IOCTL_EVENT_AER_IN_VEP, aer_in_vep_hdr),980 EV_PFF(SWITCHTEC_IOCTL_EVENT_DPC, dpc_hdr),981 EV_PFF(SWITCHTEC_IOCTL_EVENT_CTS, cts_hdr),982 EV_PFF(SWITCHTEC_IOCTL_EVENT_UEC, uec_hdr),983 EV_PFF(SWITCHTEC_IOCTL_EVENT_HOTPLUG, hotplug_hdr),984 EV_PFF(SWITCHTEC_IOCTL_EVENT_IER, ier_hdr),985 EV_PFF(SWITCHTEC_IOCTL_EVENT_THRESH, threshold_hdr),986 EV_PFF(SWITCHTEC_IOCTL_EVENT_POWER_MGMT, power_mgmt_hdr),987 EV_PFF(SWITCHTEC_IOCTL_EVENT_TLP_THROTTLING, tlp_throttling_hdr),988 EV_PFF(SWITCHTEC_IOCTL_EVENT_FORCE_SPEED, force_speed_hdr),989 EV_PFF(SWITCHTEC_IOCTL_EVENT_CREDIT_TIMEOUT, credit_timeout_hdr),990 EV_PFF(SWITCHTEC_IOCTL_EVENT_LINK_STATE, link_state_hdr),991};992 993static u32 __iomem *event_hdr_addr(struct switchtec_dev *stdev,994 int event_id, int index)995{996 size_t off;997 998 if (event_id < 0 || event_id >= SWITCHTEC_IOCTL_MAX_EVENTS)999 return (u32 __iomem *)ERR_PTR(-EINVAL);1000 1001 off = event_regs[event_id].offset;1002 1003 if (event_regs[event_id].map_reg == part_ev_reg) {1004 if (index == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX)1005 index = stdev->partition;1006 else if (index < 0 || index >= stdev->partition_count)1007 return (u32 __iomem *)ERR_PTR(-EINVAL);1008 } else if (event_regs[event_id].map_reg == pff_ev_reg) {1009 if (index < 0 || index >= stdev->pff_csr_count)1010 return (u32 __iomem *)ERR_PTR(-EINVAL);1011 }1012 1013 return event_regs[event_id].map_reg(stdev, off, index);1014}1015 1016static int event_ctl(struct switchtec_dev *stdev,1017 struct switchtec_ioctl_event_ctl *ctl)1018{1019 int i;1020 u32 __iomem *reg;1021 u32 hdr;1022 1023 reg = event_hdr_addr(stdev, ctl->event_id, ctl->index);1024 if (IS_ERR(reg))1025 return PTR_ERR(reg);1026 1027 hdr = ioread32(reg);1028 if (hdr & SWITCHTEC_EVENT_NOT_SUPP)1029 return -EOPNOTSUPP;1030 1031 for (i = 0; i < ARRAY_SIZE(ctl->data); i++)1032 ctl->data[i] = ioread32(®[i + 1]);1033 1034 ctl->occurred = hdr & SWITCHTEC_EVENT_OCCURRED;1035 ctl->count = (hdr >> 5) & 0xFF;1036 1037 if (!(ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_CLEAR))1038 hdr &= ~SWITCHTEC_EVENT_CLEAR;1039 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL)1040 hdr |= SWITCHTEC_EVENT_EN_IRQ;1041 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_POLL)1042 hdr &= ~SWITCHTEC_EVENT_EN_IRQ;1043 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_LOG)1044 hdr |= SWITCHTEC_EVENT_EN_LOG;1045 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_LOG)1046 hdr &= ~SWITCHTEC_EVENT_EN_LOG;1047 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_CLI)1048 hdr |= SWITCHTEC_EVENT_EN_CLI;1049 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_CLI)1050 hdr &= ~SWITCHTEC_EVENT_EN_CLI;1051 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_EN_FATAL)1052 hdr |= SWITCHTEC_EVENT_FATAL;1053 if (ctl->flags & SWITCHTEC_IOCTL_EVENT_FLAG_DIS_FATAL)1054 hdr &= ~SWITCHTEC_EVENT_FATAL;1055 1056 if (ctl->flags)1057 iowrite32(hdr, reg);1058 1059 ctl->flags = 0;1060 if (hdr & SWITCHTEC_EVENT_EN_IRQ)1061 ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_POLL;1062 if (hdr & SWITCHTEC_EVENT_EN_LOG)1063 ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_LOG;1064 if (hdr & SWITCHTEC_EVENT_EN_CLI)1065 ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_CLI;1066 if (hdr & SWITCHTEC_EVENT_FATAL)1067 ctl->flags |= SWITCHTEC_IOCTL_EVENT_FLAG_EN_FATAL;1068 1069 return 0;1070}1071 1072static int ioctl_event_ctl(struct switchtec_dev *stdev,1073 struct switchtec_ioctl_event_ctl __user *uctl)1074{1075 int ret;1076 int nr_idxs;1077 unsigned int event_flags;1078 struct switchtec_ioctl_event_ctl ctl;1079 1080 if (copy_from_user(&ctl, uctl, sizeof(ctl)))1081 return -EFAULT;1082 1083 if (ctl.event_id >= SWITCHTEC_IOCTL_MAX_EVENTS)1084 return -EINVAL;1085 1086 if (ctl.flags & SWITCHTEC_IOCTL_EVENT_FLAG_UNUSED)1087 return -EINVAL;1088 1089 if (ctl.index == SWITCHTEC_IOCTL_EVENT_IDX_ALL) {1090 if (event_regs[ctl.event_id].map_reg == global_ev_reg)1091 nr_idxs = 1;1092 else if (event_regs[ctl.event_id].map_reg == part_ev_reg)1093 nr_idxs = stdev->partition_count;1094 else if (event_regs[ctl.event_id].map_reg == pff_ev_reg)1095 nr_idxs = stdev->pff_csr_count;1096 else1097 return -EINVAL;1098 1099 event_flags = ctl.flags;1100 for (ctl.index = 0; ctl.index < nr_idxs; ctl.index++) {1101 ctl.flags = event_flags;1102 ret = event_ctl(stdev, &ctl);1103 if (ret < 0 && ret != -EOPNOTSUPP)1104 return ret;1105 }1106 } else {1107 ret = event_ctl(stdev, &ctl);1108 if (ret < 0)1109 return ret;1110 }1111 1112 if (copy_to_user(uctl, &ctl, sizeof(ctl)))1113 return -EFAULT;1114 1115 return 0;1116}1117 1118static int ioctl_pff_to_port(struct switchtec_dev *stdev,1119 struct switchtec_ioctl_pff_port __user *up)1120{1121 int i, part;1122 u32 reg;1123 struct part_cfg_regs __iomem *pcfg;1124 struct switchtec_ioctl_pff_port p;1125 1126 if (copy_from_user(&p, up, sizeof(p)))1127 return -EFAULT;1128 1129 p.port = -1;1130 for (part = 0; part < stdev->partition_count; part++) {1131 pcfg = &stdev->mmio_part_cfg_all[part];1132 p.partition = part;1133 1134 reg = ioread32(&pcfg->usp_pff_inst_id);1135 if (reg == p.pff) {1136 p.port = 0;1137 break;1138 }1139 1140 reg = ioread32(&pcfg->vep_pff_inst_id) & 0xFF;1141 if (reg == p.pff) {1142 p.port = SWITCHTEC_IOCTL_PFF_VEP;1143 break;1144 }1145 1146 for (i = 0; i < ARRAY_SIZE(pcfg->dsp_pff_inst_id); i++) {1147 reg = ioread32(&pcfg->dsp_pff_inst_id[i]);1148 if (reg != p.pff)1149 continue;1150 1151 p.port = i + 1;1152 break;1153 }1154 1155 if (p.port != -1)1156 break;1157 }1158 1159 if (copy_to_user(up, &p, sizeof(p)))1160 return -EFAULT;1161 1162 return 0;1163}1164 1165static int ioctl_port_to_pff(struct switchtec_dev *stdev,1166 struct switchtec_ioctl_pff_port __user *up)1167{1168 struct switchtec_ioctl_pff_port p;1169 struct part_cfg_regs __iomem *pcfg;1170 1171 if (copy_from_user(&p, up, sizeof(p)))1172 return -EFAULT;1173 1174 if (p.partition == SWITCHTEC_IOCTL_EVENT_LOCAL_PART_IDX)1175 pcfg = stdev->mmio_part_cfg;1176 else if (p.partition < stdev->partition_count)1177 pcfg = &stdev->mmio_part_cfg_all[p.partition];1178 else1179 return -EINVAL;1180 1181 switch (p.port) {1182 case 0:1183 p.pff = ioread32(&pcfg->usp_pff_inst_id);1184 break;1185 case SWITCHTEC_IOCTL_PFF_VEP:1186 p.pff = ioread32(&pcfg->vep_pff_inst_id) & 0xFF;1187 break;1188 default:1189 if (p.port > ARRAY_SIZE(pcfg->dsp_pff_inst_id))1190 return -EINVAL;1191 p.port = array_index_nospec(p.port,1192 ARRAY_SIZE(pcfg->dsp_pff_inst_id) + 1);1193 p.pff = ioread32(&pcfg->dsp_pff_inst_id[p.port - 1]);1194 break;1195 }1196 1197 if (copy_to_user(up, &p, sizeof(p)))1198 return -EFAULT;1199 1200 return 0;1201}1202 1203static long switchtec_dev_ioctl(struct file *filp, unsigned int cmd,1204 unsigned long arg)1205{1206 struct switchtec_user *stuser = filp->private_data;1207 struct switchtec_dev *stdev = stuser->stdev;1208 int rc;1209 void __user *argp = (void __user *)arg;1210 1211 rc = lock_mutex_and_test_alive(stdev);1212 if (rc)1213 return rc;1214 1215 switch (cmd) {1216 case SWITCHTEC_IOCTL_FLASH_INFO:1217 rc = ioctl_flash_info(stdev, argp);1218 break;1219 case SWITCHTEC_IOCTL_FLASH_PART_INFO:1220 rc = ioctl_flash_part_info(stdev, argp);1221 break;1222 case SWITCHTEC_IOCTL_EVENT_SUMMARY_LEGACY:1223 rc = ioctl_event_summary(stdev, stuser, argp,1224 sizeof(struct switchtec_ioctl_event_summary_legacy));1225 break;1226 case SWITCHTEC_IOCTL_EVENT_CTL:1227 rc = ioctl_event_ctl(stdev, argp);1228 break;1229 case SWITCHTEC_IOCTL_PFF_TO_PORT:1230 rc = ioctl_pff_to_port(stdev, argp);1231 break;1232 case SWITCHTEC_IOCTL_PORT_TO_PFF:1233 rc = ioctl_port_to_pff(stdev, argp);1234 break;1235 case SWITCHTEC_IOCTL_EVENT_SUMMARY:1236 rc = ioctl_event_summary(stdev, stuser, argp,1237 sizeof(struct switchtec_ioctl_event_summary));1238 break;1239 default:1240 rc = -ENOTTY;1241 break;1242 }1243 1244 mutex_unlock(&stdev->mrpc_mutex);1245 return rc;1246}1247 1248static const struct file_operations switchtec_fops = {1249 .owner = THIS_MODULE,1250 .open = switchtec_dev_open,1251 .release = switchtec_dev_release,1252 .write = switchtec_dev_write,1253 .read = switchtec_dev_read,1254 .poll = switchtec_dev_poll,1255 .unlocked_ioctl = switchtec_dev_ioctl,1256 .compat_ioctl = compat_ptr_ioctl,1257};1258 1259static void link_event_work(struct work_struct *work)1260{1261 struct switchtec_dev *stdev;1262 1263 stdev = container_of(work, struct switchtec_dev, link_event_work);1264 1265 if (stdev->link_notifier)1266 stdev->link_notifier(stdev);1267}1268 1269static void check_link_state_events(struct switchtec_dev *stdev)1270{1271 int idx;1272 u32 reg;1273 int count;1274 int occurred = 0;1275 1276 for (idx = 0; idx < stdev->pff_csr_count; idx++) {1277 reg = ioread32(&stdev->mmio_pff_csr[idx].link_state_hdr);1278 dev_dbg(&stdev->dev, "link_state: %d->%08x\n", idx, reg);1279 count = (reg >> 5) & 0xFF;1280 1281 if (count != stdev->link_event_count[idx]) {1282 occurred = 1;1283 stdev->link_event_count[idx] = count;1284 }1285 }1286 1287 if (occurred)1288 schedule_work(&stdev->link_event_work);1289}1290 1291static void enable_link_state_events(struct switchtec_dev *stdev)1292{1293 int idx;1294 1295 for (idx = 0; idx < stdev->pff_csr_count; idx++) {1296 iowrite32(SWITCHTEC_EVENT_CLEAR |1297 SWITCHTEC_EVENT_EN_IRQ,1298 &stdev->mmio_pff_csr[idx].link_state_hdr);1299 }1300}1301 1302static void enable_dma_mrpc(struct switchtec_dev *stdev)1303{1304 writeq(stdev->dma_mrpc_dma_addr, &stdev->mmio_mrpc->dma_addr);1305 flush_wc_buf(stdev);1306 iowrite32(SWITCHTEC_DMA_MRPC_EN, &stdev->mmio_mrpc->dma_en);1307}1308 1309static void stdev_release(struct device *dev)1310{1311 struct switchtec_dev *stdev = to_stdev(dev);1312 1313 kfree(stdev);1314}1315 1316static void stdev_kill(struct switchtec_dev *stdev)1317{1318 struct switchtec_user *stuser, *tmpuser;1319 1320 pci_clear_master(stdev->pdev);1321 1322 cancel_delayed_work_sync(&stdev->mrpc_timeout);1323 1324 /* Mark the hardware as unavailable and complete all completions */1325 mutex_lock(&stdev->mrpc_mutex);1326 stdev->alive = false;1327 1328 /* Wake up and kill any users waiting on an MRPC request */1329 list_for_each_entry_safe(stuser, tmpuser, &stdev->mrpc_queue, list) {1330 stuser->cmd_done = true;1331 wake_up_interruptible(&stuser->cmd_comp);1332 list_del_init(&stuser->list);1333 stuser_put(stuser);1334 }1335 1336 mutex_unlock(&stdev->mrpc_mutex);1337 1338 /* Wake up any users waiting on event_wq */1339 wake_up_interruptible(&stdev->event_wq);1340}1341 1342static struct switchtec_dev *stdev_create(struct pci_dev *pdev)1343{1344 struct switchtec_dev *stdev;1345 int minor;1346 struct device *dev;1347 struct cdev *cdev;1348 int rc;1349 1350 stdev = kzalloc_node(sizeof(*stdev), GFP_KERNEL,1351 dev_to_node(&pdev->dev));1352 if (!stdev)1353 return ERR_PTR(-ENOMEM);1354 1355 stdev->alive = true;1356 stdev->pdev = pci_dev_get(pdev);1357 INIT_LIST_HEAD(&stdev->mrpc_queue);1358 mutex_init(&stdev->mrpc_mutex);1359 stdev->mrpc_busy = 0;1360 INIT_WORK(&stdev->mrpc_work, mrpc_event_work);1361 INIT_DELAYED_WORK(&stdev->mrpc_timeout, mrpc_timeout_work);1362 INIT_WORK(&stdev->link_event_work, link_event_work);1363 init_waitqueue_head(&stdev->event_wq);1364 atomic_set(&stdev->event_cnt, 0);1365 1366 dev = &stdev->dev;1367 device_initialize(dev);1368 dev->class = &switchtec_class;1369 dev->parent = &pdev->dev;1370 dev->groups = switchtec_device_groups;1371 dev->release = stdev_release;1372 1373 minor = ida_alloc(&switchtec_minor_ida, GFP_KERNEL);1374 if (minor < 0) {1375 rc = minor;1376 goto err_put;1377 }1378 1379 dev->devt = MKDEV(MAJOR(switchtec_devt), minor);1380 dev_set_name(dev, "switchtec%d", minor);1381 1382 cdev = &stdev->cdev;1383 cdev_init(cdev, &switchtec_fops);1384 cdev->owner = THIS_MODULE;1385 1386 return stdev;1387 1388err_put:1389 pci_dev_put(stdev->pdev);1390 put_device(&stdev->dev);1391 return ERR_PTR(rc);1392}1393 1394static int mask_event(struct switchtec_dev *stdev, int eid, int idx)1395{1396 size_t off = event_regs[eid].offset;1397 u32 __iomem *hdr_reg;1398 u32 hdr;1399 1400 hdr_reg = event_regs[eid].map_reg(stdev, off, idx);1401 hdr = ioread32(hdr_reg);1402 1403 if (hdr & SWITCHTEC_EVENT_NOT_SUPP)1404 return 0;1405 1406 if (!(hdr & SWITCHTEC_EVENT_OCCURRED && hdr & SWITCHTEC_EVENT_EN_IRQ))1407 return 0;1408 1409 dev_dbg(&stdev->dev, "%s: %d %d %x\n", __func__, eid, idx, hdr);1410 hdr &= ~(SWITCHTEC_EVENT_EN_IRQ | SWITCHTEC_EVENT_OCCURRED);1411 iowrite32(hdr, hdr_reg);1412 1413 return 1;1414}1415 1416static int mask_all_events(struct switchtec_dev *stdev, int eid)1417{1418 int idx;1419 int count = 0;1420 1421 if (event_regs[eid].map_reg == part_ev_reg) {1422 for (idx = 0; idx < stdev->partition_count; idx++)1423 count += mask_event(stdev, eid, idx);1424 } else if (event_regs[eid].map_reg == pff_ev_reg) {1425 for (idx = 0; idx < stdev->pff_csr_count; idx++) {1426 if (!stdev->pff_local[idx])1427 continue;1428 1429 count += mask_event(stdev, eid, idx);1430 }1431 } else {1432 count += mask_event(stdev, eid, 0);1433 }1434 1435 return count;1436}1437 1438static irqreturn_t switchtec_event_isr(int irq, void *dev)1439{1440 struct switchtec_dev *stdev = dev;1441 u32 reg;1442 irqreturn_t ret = IRQ_NONE;1443 int eid, event_count = 0;1444 1445 reg = ioread32(&stdev->mmio_part_cfg->mrpc_comp_hdr);1446 if (reg & SWITCHTEC_EVENT_OCCURRED) {1447 dev_dbg(&stdev->dev, "%s: mrpc comp\n", __func__);1448 ret = IRQ_HANDLED;1449 schedule_work(&stdev->mrpc_work);1450 iowrite32(reg, &stdev->mmio_part_cfg->mrpc_comp_hdr);1451 }1452 1453 check_link_state_events(stdev);1454 1455 for (eid = 0; eid < SWITCHTEC_IOCTL_MAX_EVENTS; eid++) {1456 if (eid == SWITCHTEC_IOCTL_EVENT_LINK_STATE ||1457 eid == SWITCHTEC_IOCTL_EVENT_MRPC_COMP)1458 continue;1459 1460 event_count += mask_all_events(stdev, eid);1461 }1462 1463 if (event_count) {1464 atomic_inc(&stdev->event_cnt);1465 wake_up_interruptible(&stdev->event_wq);1466 dev_dbg(&stdev->dev, "%s: %d events\n", __func__,1467 event_count);1468 return IRQ_HANDLED;1469 }1470 1471 return ret;1472}1473 1474 1475static irqreturn_t switchtec_dma_mrpc_isr(int irq, void *dev)1476{1477 struct switchtec_dev *stdev = dev;1478 1479 iowrite32(SWITCHTEC_EVENT_CLEAR |1480 SWITCHTEC_EVENT_EN_IRQ,1481 &stdev->mmio_part_cfg->mrpc_comp_hdr);1482 schedule_work(&stdev->mrpc_work);1483 1484 return IRQ_HANDLED;1485}1486 1487static int switchtec_init_isr(struct switchtec_dev *stdev)1488{1489 int nvecs;1490 int event_irq;1491 int dma_mrpc_irq;1492 int rc;1493 1494 if (nirqs < 4)1495 nirqs = 4;1496 1497 nvecs = pci_alloc_irq_vectors(stdev->pdev, 1, nirqs,1498 PCI_IRQ_MSIX | PCI_IRQ_MSI |1499 PCI_IRQ_VIRTUAL);1500 if (nvecs < 0)1501 return nvecs;1502 1503 event_irq = ioread16(&stdev->mmio_part_cfg->vep_vector_number);1504 if (event_irq < 0 || event_irq >= nvecs)1505 return -EFAULT;1506 1507 event_irq = pci_irq_vector(stdev->pdev, event_irq);1508 if (event_irq < 0)1509 return event_irq;1510 1511 rc = devm_request_irq(&stdev->pdev->dev, event_irq,1512 switchtec_event_isr, 0,1513 KBUILD_MODNAME, stdev);1514 1515 if (rc)1516 return rc;1517 1518 if (!stdev->dma_mrpc)1519 return rc;1520 1521 dma_mrpc_irq = ioread32(&stdev->mmio_mrpc->dma_vector);1522 if (dma_mrpc_irq < 0 || dma_mrpc_irq >= nvecs)1523 return -EFAULT;1524 1525 dma_mrpc_irq = pci_irq_vector(stdev->pdev, dma_mrpc_irq);1526 if (dma_mrpc_irq < 0)1527 return dma_mrpc_irq;1528 1529 rc = devm_request_irq(&stdev->pdev->dev, dma_mrpc_irq,1530 switchtec_dma_mrpc_isr, 0,1531 KBUILD_MODNAME, stdev);1532 1533 return rc;1534}1535 1536static void init_pff(struct switchtec_dev *stdev)1537{1538 int i;1539 u32 reg;1540 struct part_cfg_regs __iomem *pcfg = stdev->mmio_part_cfg;1541 1542 for (i = 0; i < SWITCHTEC_MAX_PFF_CSR; i++) {1543 reg = ioread16(&stdev->mmio_pff_csr[i].vendor_id);1544 if (reg != PCI_VENDOR_ID_MICROSEMI)1545 break;1546 }1547 1548 stdev->pff_csr_count = i;1549 1550 reg = ioread32(&pcfg->usp_pff_inst_id);1551 if (reg < stdev->pff_csr_count)1552 stdev->pff_local[reg] = 1;1553 1554 reg = ioread32(&pcfg->vep_pff_inst_id) & 0xFF;1555 if (reg < stdev->pff_csr_count)1556 stdev->pff_local[reg] = 1;1557 1558 for (i = 0; i < ARRAY_SIZE(pcfg->dsp_pff_inst_id); i++) {1559 reg = ioread32(&pcfg->dsp_pff_inst_id[i]);1560 if (reg < stdev->pff_csr_count)1561 stdev->pff_local[reg] = 1;1562 }1563}1564 1565static int switchtec_init_pci(struct switchtec_dev *stdev,1566 struct pci_dev *pdev)1567{1568 int rc;1569 void __iomem *map;1570 unsigned long res_start, res_len;1571 u32 __iomem *part_id;1572 1573 rc = pcim_enable_device(pdev);1574 if (rc)1575 return rc;1576 1577 rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));1578 if (rc)1579 return rc;1580 1581 pci_set_master(pdev);1582 1583 res_start = pci_resource_start(pdev, 0);1584 res_len = pci_resource_len(pdev, 0);1585 1586 if (!devm_request_mem_region(&pdev->dev, res_start,1587 res_len, KBUILD_MODNAME))1588 return -EBUSY;1589 1590 stdev->mmio_mrpc = devm_ioremap_wc(&pdev->dev, res_start,1591 SWITCHTEC_GAS_TOP_CFG_OFFSET);1592 if (!stdev->mmio_mrpc)1593 return -ENOMEM;1594 1595 map = devm_ioremap(&pdev->dev,1596 res_start + SWITCHTEC_GAS_TOP_CFG_OFFSET,1597 res_len - SWITCHTEC_GAS_TOP_CFG_OFFSET);1598 if (!map)1599 return -ENOMEM;1600 1601 stdev->mmio = map - SWITCHTEC_GAS_TOP_CFG_OFFSET;1602 stdev->mmio_sw_event = stdev->mmio + SWITCHTEC_GAS_SW_EVENT_OFFSET;1603 stdev->mmio_sys_info = stdev->mmio + SWITCHTEC_GAS_SYS_INFO_OFFSET;1604 stdev->mmio_flash_info = stdev->mmio + SWITCHTEC_GAS_FLASH_INFO_OFFSET;1605 stdev->mmio_ntb = stdev->mmio + SWITCHTEC_GAS_NTB_OFFSET;1606 1607 if (stdev->gen == SWITCHTEC_GEN3)1608 part_id = &stdev->mmio_sys_info->gen3.partition_id;1609 else if (stdev->gen >= SWITCHTEC_GEN4)1610 part_id = &stdev->mmio_sys_info->gen4.partition_id;1611 else1612 return -EOPNOTSUPP;1613 1614 stdev->partition = ioread8(part_id);1615 stdev->partition_count = ioread8(&stdev->mmio_ntb->partition_count);1616 stdev->mmio_part_cfg_all = stdev->mmio + SWITCHTEC_GAS_PART_CFG_OFFSET;1617 stdev->mmio_part_cfg = &stdev->mmio_part_cfg_all[stdev->partition];1618 stdev->mmio_pff_csr = stdev->mmio + SWITCHTEC_GAS_PFF_CSR_OFFSET;1619 1620 if (stdev->partition_count < 1)1621 stdev->partition_count = 1;1622 1623 init_pff(stdev);1624 1625 pci_set_drvdata(pdev, stdev);1626 1627 if (!use_dma_mrpc)1628 return 0;1629 1630 if (ioread32(&stdev->mmio_mrpc->dma_ver) == 0)1631 return 0;1632 1633 stdev->dma_mrpc = dma_alloc_coherent(&stdev->pdev->dev,1634 sizeof(*stdev->dma_mrpc),1635 &stdev->dma_mrpc_dma_addr,1636 GFP_KERNEL);1637 if (stdev->dma_mrpc == NULL)1638 return -ENOMEM;1639 1640 return 0;1641}1642 1643static void switchtec_exit_pci(struct switchtec_dev *stdev)1644{1645 if (stdev->dma_mrpc) {1646 iowrite32(0, &stdev->mmio_mrpc->dma_en);1647 flush_wc_buf(stdev);1648 writeq(0, &stdev->mmio_mrpc->dma_addr);1649 dma_free_coherent(&stdev->pdev->dev, sizeof(*stdev->dma_mrpc),1650 stdev->dma_mrpc, stdev->dma_mrpc_dma_addr);1651 stdev->dma_mrpc = NULL;1652 }1653}1654 1655static int switchtec_pci_probe(struct pci_dev *pdev,1656 const struct pci_device_id *id)1657{1658 struct switchtec_dev *stdev;1659 int rc;1660 1661 if (pdev->class == (PCI_CLASS_BRIDGE_OTHER << 8))1662 request_module_nowait("ntb_hw_switchtec");1663 1664 stdev = stdev_create(pdev);1665 if (IS_ERR(stdev))1666 return PTR_ERR(stdev);1667 1668 stdev->gen = id->driver_data;1669 1670 rc = switchtec_init_pci(stdev, pdev);1671 if (rc)1672 goto err_put;1673 1674 rc = switchtec_init_isr(stdev);1675 if (rc) {1676 dev_err(&stdev->dev, "failed to init isr.\n");1677 goto err_exit_pci;1678 }1679 1680 iowrite32(SWITCHTEC_EVENT_CLEAR |1681 SWITCHTEC_EVENT_EN_IRQ,1682 &stdev->mmio_part_cfg->mrpc_comp_hdr);1683 enable_link_state_events(stdev);1684 1685 if (stdev->dma_mrpc)1686 enable_dma_mrpc(stdev);1687 1688 rc = cdev_device_add(&stdev->cdev, &stdev->dev);1689 if (rc)1690 goto err_devadd;1691 1692 dev_info(&stdev->dev, "Management device registered.\n");1693 1694 return 0;1695 1696err_devadd:1697 stdev_kill(stdev);1698err_exit_pci:1699 switchtec_exit_pci(stdev);1700err_put:1701 ida_free(&switchtec_minor_ida, MINOR(stdev->dev.devt));1702 put_device(&stdev->dev);1703 return rc;1704}1705 1706static void switchtec_pci_remove(struct pci_dev *pdev)1707{1708 struct switchtec_dev *stdev = pci_get_drvdata(pdev);1709 1710 pci_set_drvdata(pdev, NULL);1711 1712 cdev_device_del(&stdev->cdev, &stdev->dev);1713 ida_free(&switchtec_minor_ida, MINOR(stdev->dev.devt));1714 dev_info(&stdev->dev, "unregistered.\n");1715 stdev_kill(stdev);1716 switchtec_exit_pci(stdev);1717 pci_dev_put(stdev->pdev);1718 stdev->pdev = NULL;1719 put_device(&stdev->dev);1720}1721 1722#define SWITCHTEC_PCI_DEVICE(device_id, gen) \1723 { \1724 .vendor = PCI_VENDOR_ID_MICROSEMI, \1725 .device = device_id, \1726 .subvendor = PCI_ANY_ID, \1727 .subdevice = PCI_ANY_ID, \1728 .class = (PCI_CLASS_MEMORY_OTHER << 8), \1729 .class_mask = 0xFFFFFFFF, \1730 .driver_data = gen, \1731 }, \1732 { \1733 .vendor = PCI_VENDOR_ID_MICROSEMI, \1734 .device = device_id, \1735 .subvendor = PCI_ANY_ID, \1736 .subdevice = PCI_ANY_ID, \1737 .class = (PCI_CLASS_BRIDGE_OTHER << 8), \1738 .class_mask = 0xFFFFFFFF, \1739 .driver_data = gen, \1740 }1741 1742static const struct pci_device_id switchtec_pci_tbl[] = {1743 SWITCHTEC_PCI_DEVICE(0x8531, SWITCHTEC_GEN3), /* PFX 24xG3 */1744 SWITCHTEC_PCI_DEVICE(0x8532, SWITCHTEC_GEN3), /* PFX 32xG3 */1745 SWITCHTEC_PCI_DEVICE(0x8533, SWITCHTEC_GEN3), /* PFX 48xG3 */1746 SWITCHTEC_PCI_DEVICE(0x8534, SWITCHTEC_GEN3), /* PFX 64xG3 */1747 SWITCHTEC_PCI_DEVICE(0x8535, SWITCHTEC_GEN3), /* PFX 80xG3 */1748 SWITCHTEC_PCI_DEVICE(0x8536, SWITCHTEC_GEN3), /* PFX 96xG3 */1749 SWITCHTEC_PCI_DEVICE(0x8541, SWITCHTEC_GEN3), /* PSX 24xG3 */1750 SWITCHTEC_PCI_DEVICE(0x8542, SWITCHTEC_GEN3), /* PSX 32xG3 */1751 SWITCHTEC_PCI_DEVICE(0x8543, SWITCHTEC_GEN3), /* PSX 48xG3 */1752 SWITCHTEC_PCI_DEVICE(0x8544, SWITCHTEC_GEN3), /* PSX 64xG3 */1753 SWITCHTEC_PCI_DEVICE(0x8545, SWITCHTEC_GEN3), /* PSX 80xG3 */1754 SWITCHTEC_PCI_DEVICE(0x8546, SWITCHTEC_GEN3), /* PSX 96xG3 */1755 SWITCHTEC_PCI_DEVICE(0x8551, SWITCHTEC_GEN3), /* PAX 24XG3 */1756 SWITCHTEC_PCI_DEVICE(0x8552, SWITCHTEC_GEN3), /* PAX 32XG3 */1757 SWITCHTEC_PCI_DEVICE(0x8553, SWITCHTEC_GEN3), /* PAX 48XG3 */1758 SWITCHTEC_PCI_DEVICE(0x8554, SWITCHTEC_GEN3), /* PAX 64XG3 */1759 SWITCHTEC_PCI_DEVICE(0x8555, SWITCHTEC_GEN3), /* PAX 80XG3 */1760 SWITCHTEC_PCI_DEVICE(0x8556, SWITCHTEC_GEN3), /* PAX 96XG3 */1761 SWITCHTEC_PCI_DEVICE(0x8561, SWITCHTEC_GEN3), /* PFXL 24XG3 */1762 SWITCHTEC_PCI_DEVICE(0x8562, SWITCHTEC_GEN3), /* PFXL 32XG3 */1763 SWITCHTEC_PCI_DEVICE(0x8563, SWITCHTEC_GEN3), /* PFXL 48XG3 */1764 SWITCHTEC_PCI_DEVICE(0x8564, SWITCHTEC_GEN3), /* PFXL 64XG3 */1765 SWITCHTEC_PCI_DEVICE(0x8565, SWITCHTEC_GEN3), /* PFXL 80XG3 */1766 SWITCHTEC_PCI_DEVICE(0x8566, SWITCHTEC_GEN3), /* PFXL 96XG3 */1767 SWITCHTEC_PCI_DEVICE(0x8571, SWITCHTEC_GEN3), /* PFXI 24XG3 */1768 SWITCHTEC_PCI_DEVICE(0x8572, SWITCHTEC_GEN3), /* PFXI 32XG3 */1769 SWITCHTEC_PCI_DEVICE(0x8573, SWITCHTEC_GEN3), /* PFXI 48XG3 */1770 SWITCHTEC_PCI_DEVICE(0x8574, SWITCHTEC_GEN3), /* PFXI 64XG3 */1771 SWITCHTEC_PCI_DEVICE(0x8575, SWITCHTEC_GEN3), /* PFXI 80XG3 */1772 SWITCHTEC_PCI_DEVICE(0x8576, SWITCHTEC_GEN3), /* PFXI 96XG3 */1773 SWITCHTEC_PCI_DEVICE(0x4000, SWITCHTEC_GEN4), /* PFX 100XG4 */1774 SWITCHTEC_PCI_DEVICE(0x4084, SWITCHTEC_GEN4), /* PFX 84XG4 */1775 SWITCHTEC_PCI_DEVICE(0x4068, SWITCHTEC_GEN4), /* PFX 68XG4 */1776 SWITCHTEC_PCI_DEVICE(0x4052, SWITCHTEC_GEN4), /* PFX 52XG4 */1777 SWITCHTEC_PCI_DEVICE(0x4036, SWITCHTEC_GEN4), /* PFX 36XG4 */1778 SWITCHTEC_PCI_DEVICE(0x4028, SWITCHTEC_GEN4), /* PFX 28XG4 */1779 SWITCHTEC_PCI_DEVICE(0x4100, SWITCHTEC_GEN4), /* PSX 100XG4 */1780 SWITCHTEC_PCI_DEVICE(0x4184, SWITCHTEC_GEN4), /* PSX 84XG4 */1781 SWITCHTEC_PCI_DEVICE(0x4168, SWITCHTEC_GEN4), /* PSX 68XG4 */1782 SWITCHTEC_PCI_DEVICE(0x4152, SWITCHTEC_GEN4), /* PSX 52XG4 */1783 SWITCHTEC_PCI_DEVICE(0x4136, SWITCHTEC_GEN4), /* PSX 36XG4 */1784 SWITCHTEC_PCI_DEVICE(0x4128, SWITCHTEC_GEN4), /* PSX 28XG4 */1785 SWITCHTEC_PCI_DEVICE(0x4200, SWITCHTEC_GEN4), /* PAX 100XG4 */1786 SWITCHTEC_PCI_DEVICE(0x4284, SWITCHTEC_GEN4), /* PAX 84XG4 */1787 SWITCHTEC_PCI_DEVICE(0x4268, SWITCHTEC_GEN4), /* PAX 68XG4 */1788 SWITCHTEC_PCI_DEVICE(0x4252, SWITCHTEC_GEN4), /* PAX 52XG4 */1789 SWITCHTEC_PCI_DEVICE(0x4236, SWITCHTEC_GEN4), /* PAX 36XG4 */1790 SWITCHTEC_PCI_DEVICE(0x4228, SWITCHTEC_GEN4), /* PAX 28XG4 */1791 SWITCHTEC_PCI_DEVICE(0x4352, SWITCHTEC_GEN4), /* PFXA 52XG4 */1792 SWITCHTEC_PCI_DEVICE(0x4336, SWITCHTEC_GEN4), /* PFXA 36XG4 */1793 SWITCHTEC_PCI_DEVICE(0x4328, SWITCHTEC_GEN4), /* PFXA 28XG4 */1794 SWITCHTEC_PCI_DEVICE(0x4452, SWITCHTEC_GEN4), /* PSXA 52XG4 */1795 SWITCHTEC_PCI_DEVICE(0x4436, SWITCHTEC_GEN4), /* PSXA 36XG4 */1796 SWITCHTEC_PCI_DEVICE(0x4428, SWITCHTEC_GEN4), /* PSXA 28XG4 */1797 SWITCHTEC_PCI_DEVICE(0x4552, SWITCHTEC_GEN4), /* PAXA 52XG4 */1798 SWITCHTEC_PCI_DEVICE(0x4536, SWITCHTEC_GEN4), /* PAXA 36XG4 */1799 SWITCHTEC_PCI_DEVICE(0x4528, SWITCHTEC_GEN4), /* PAXA 28XG4 */1800 SWITCHTEC_PCI_DEVICE(0x5000, SWITCHTEC_GEN5), /* PFX 100XG5 */1801 SWITCHTEC_PCI_DEVICE(0x5084, SWITCHTEC_GEN5), /* PFX 84XG5 */1802 SWITCHTEC_PCI_DEVICE(0x5068, SWITCHTEC_GEN5), /* PFX 68XG5 */1803 SWITCHTEC_PCI_DEVICE(0x5052, SWITCHTEC_GEN5), /* PFX 52XG5 */1804 SWITCHTEC_PCI_DEVICE(0x5036, SWITCHTEC_GEN5), /* PFX 36XG5 */1805 SWITCHTEC_PCI_DEVICE(0x5028, SWITCHTEC_GEN5), /* PFX 28XG5 */1806 SWITCHTEC_PCI_DEVICE(0x5100, SWITCHTEC_GEN5), /* PSX 100XG5 */1807 SWITCHTEC_PCI_DEVICE(0x5184, SWITCHTEC_GEN5), /* PSX 84XG5 */1808 SWITCHTEC_PCI_DEVICE(0x5168, SWITCHTEC_GEN5), /* PSX 68XG5 */1809 SWITCHTEC_PCI_DEVICE(0x5152, SWITCHTEC_GEN5), /* PSX 52XG5 */1810 SWITCHTEC_PCI_DEVICE(0x5136, SWITCHTEC_GEN5), /* PSX 36XG5 */1811 SWITCHTEC_PCI_DEVICE(0x5128, SWITCHTEC_GEN5), /* PSX 28XG5 */1812 SWITCHTEC_PCI_DEVICE(0x5200, SWITCHTEC_GEN5), /* PAX 100XG5 */1813 SWITCHTEC_PCI_DEVICE(0x5284, SWITCHTEC_GEN5), /* PAX 84XG5 */1814 SWITCHTEC_PCI_DEVICE(0x5268, SWITCHTEC_GEN5), /* PAX 68XG5 */1815 SWITCHTEC_PCI_DEVICE(0x5252, SWITCHTEC_GEN5), /* PAX 52XG5 */1816 SWITCHTEC_PCI_DEVICE(0x5236, SWITCHTEC_GEN5), /* PAX 36XG5 */1817 SWITCHTEC_PCI_DEVICE(0x5228, SWITCHTEC_GEN5), /* PAX 28XG5 */1818 SWITCHTEC_PCI_DEVICE(0x5300, SWITCHTEC_GEN5), /* PFXA 100XG5 */1819 SWITCHTEC_PCI_DEVICE(0x5384, SWITCHTEC_GEN5), /* PFXA 84XG5 */1820 SWITCHTEC_PCI_DEVICE(0x5368, SWITCHTEC_GEN5), /* PFXA 68XG5 */1821 SWITCHTEC_PCI_DEVICE(0x5352, SWITCHTEC_GEN5), /* PFXA 52XG5 */1822 SWITCHTEC_PCI_DEVICE(0x5336, SWITCHTEC_GEN5), /* PFXA 36XG5 */1823 SWITCHTEC_PCI_DEVICE(0x5328, SWITCHTEC_GEN5), /* PFXA 28XG5 */1824 SWITCHTEC_PCI_DEVICE(0x5400, SWITCHTEC_GEN5), /* PSXA 100XG5 */1825 SWITCHTEC_PCI_DEVICE(0x5484, SWITCHTEC_GEN5), /* PSXA 84XG5 */1826 SWITCHTEC_PCI_DEVICE(0x5468, SWITCHTEC_GEN5), /* PSXA 68XG5 */1827 SWITCHTEC_PCI_DEVICE(0x5452, SWITCHTEC_GEN5), /* PSXA 52XG5 */1828 SWITCHTEC_PCI_DEVICE(0x5436, SWITCHTEC_GEN5), /* PSXA 36XG5 */1829 SWITCHTEC_PCI_DEVICE(0x5428, SWITCHTEC_GEN5), /* PSXA 28XG5 */1830 SWITCHTEC_PCI_DEVICE(0x5500, SWITCHTEC_GEN5), /* PAXA 100XG5 */1831 SWITCHTEC_PCI_DEVICE(0x5584, SWITCHTEC_GEN5), /* PAXA 84XG5 */1832 SWITCHTEC_PCI_DEVICE(0x5568, SWITCHTEC_GEN5), /* PAXA 68XG5 */1833 SWITCHTEC_PCI_DEVICE(0x5552, SWITCHTEC_GEN5), /* PAXA 52XG5 */1834 SWITCHTEC_PCI_DEVICE(0x5536, SWITCHTEC_GEN5), /* PAXA 36XG5 */1835 SWITCHTEC_PCI_DEVICE(0x5528, SWITCHTEC_GEN5), /* PAXA 28XG5 */1836 {0}1837};1838MODULE_DEVICE_TABLE(pci, switchtec_pci_tbl);1839 1840static struct pci_driver switchtec_pci_driver = {1841 .name = KBUILD_MODNAME,1842 .id_table = switchtec_pci_tbl,1843 .probe = switchtec_pci_probe,1844 .remove = switchtec_pci_remove,1845};1846 1847static int __init switchtec_init(void)1848{1849 int rc;1850 1851 rc = alloc_chrdev_region(&switchtec_devt, 0, max_devices,1852 "switchtec");1853 if (rc)1854 return rc;1855 1856 rc = class_register(&switchtec_class);1857 if (rc)1858 goto err_create_class;1859 1860 rc = pci_register_driver(&switchtec_pci_driver);1861 if (rc)1862 goto err_pci_register;1863 1864 pr_info(KBUILD_MODNAME ": loaded.\n");1865 1866 return 0;1867 1868err_pci_register:1869 class_unregister(&switchtec_class);1870 1871err_create_class:1872 unregister_chrdev_region(switchtec_devt, max_devices);1873 1874 return rc;1875}1876module_init(switchtec_init);1877 1878static void __exit switchtec_exit(void)1879{1880 pci_unregister_driver(&switchtec_pci_driver);1881 class_unregister(&switchtec_class);1882 unregister_chrdev_region(switchtec_devt, max_devices);1883 ida_destroy(&switchtec_minor_ida);1884 1885 pr_info(KBUILD_MODNAME ": unloaded.\n");1886}1887module_exit(switchtec_exit);1888